xref: /titanic_51/usr/src/cmd/mdb/common/modules/sdbc/sdbc.c (revision bfed486ad8de8b8ebc6345a8e10accae08bf2f45)
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 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <sys/mdb_modapi.h>
27 #include <sys/nsc_thread.h>
28 
29 /* needed to maintain identical _sd_bitmap_t sizes */
30 #define	_SD_8K_BLKSIZE
31 #include <sys/nsctl/sd_bcache.h>
32 
33 #include <ns/sdbc/sd_io.h>
34 #include <ns/sdbc/sd_ft.h>
35 #include <ns/sdbc/safestore.h>
36 
37 /*
38  * initialize cd filter options to this
39  * to differentiate with kernel values in range [-1, sdbc_max_devs]
40  */
41 #define	MDB_CD ((uintptr_t)~1)
42 #define	OPT_C_SELECTED (opt_c != MDB_CD)
43 
44 /* initialize block filters to this */
45 #define	MDB_BLKNUM ((uintptr_t)~1)
46 #define	OPT_B_SELECTED (opt_b != MDB_BLKNUM)
47 
48 enum vartype { UINTTYPE = 0, ADDRTYPE, LOCKTYPE, CVTYPE };
49 
50 static void display_var(char *, enum vartype);
51 #ifdef SAFESTORE
52 static void print_wrq(_sd_writeq_t *, uint_t);
53 #endif
54 
55 struct walk_info {
56 		uintptr_t w_start;
57 		uintptr_t w_end;
58 };
59 
60 
61 mdb_bitmask_t host_states[] = {
62 	{ "HOST_NONE", 0xff, _SD_HOST_NONE },
63 	{ "HOST_CONFIGURED", 0xff, _SD_HOST_CONFIGURED },
64 	{ "HOST_DECONFIGURED", 0xff, _SD_HOST_DECONFIGURED },
65 	{ "HOST_NOCACHE", 0xff, _SD_HOST_NOCACHE },
66 	{ NULL, 0, 0 }
67 
68 };
69 
70 mdb_bitmask_t cache_hints[] = {
71 	{ "WRTHRU", NSC_WRTHRU, NSC_WRTHRU },
72 	{ "FORCED_WRTHRU", NSC_FORCED_WRTHRU, NSC_FORCED_WRTHRU },
73 	{ "NOCACHE", NSC_NOCACHE, NSC_NOCACHE },
74 	{ "QUEUE", NSC_QUEUE, NSC_QUEUE },
75 	{ "RDAHEAD", NSC_RDAHEAD, NSC_RDAHEAD },
76 	{ "NO_FORCED_WRTHRU", NSC_NO_FORCED_WRTHRU, NSC_NO_FORCED_WRTHRU },
77 	{ "METADATA", NSC_METADATA, NSC_METADATA },
78 	{ "SEQ_IO", NSC_SEQ_IO, NSC_SEQ_IO },
79 	{ NULL, 0, 0 }
80 
81 };
82 
83 
84 /*
85  * some cache general dcmds that do not use walkers
86  */
87 /*ARGSUSED*/
88 static int
89 sdbc_config(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
90 {
91 	_sd_cache_param_t _sd_cache_config;
92 	_sd_net_t _sd_net_config;
93 	_sd_ft_info_t  _sd_ft_data;
94 	uint_t _sd_node_hint;
95 	char sdbc_version[17];
96 
97 	if (mdb_readvar(sdbc_version, "sdbc_version") == -1) {
98 		mdb_warn("failed to read sdbc_version symbol");
99 	} else {
100 		sdbc_version[16] = '\0';  /* make sure string is terminated */
101 		mdb_printf("sdbc_version %s\n", sdbc_version);
102 	}
103 
104 	if (mdb_readvar(&_sd_cache_config, "_sd_cache_config") == -1) {
105 		mdb_warn("failed to read _sd_cache_config symbol");
106 	} else {
107 
108 		mdb_printf("SDBC Configuration:\n");
109 		mdb_inc_indent(4);
110 		mdb_printf("user magic: %X kernel magic: %X (should match)\n",
111 			    _SD_MAGIC, _sd_cache_config.magic);
112 		mdb_printf(
113 		    "mirror host: %2d Block size: %4d threads %4d "
114 		    "write cache: %4dM\n",
115 			    _sd_cache_config.mirror_host,
116 			    _sd_cache_config.blk_size,
117 			    _sd_cache_config.threads,
118 			    _sd_cache_config.write_cache);
119 		mdb_printf("num_handles %4-d cache_mem %4dM prot_lru %d\n",
120 			    _sd_cache_config.num_handles,
121 			    _sd_cache_config.cache_mem[0],
122 			    _sd_cache_config.prot_lru);
123 		mdb_printf("gen_pattern %d fill_pattern %?-p num_nodes %d\n",
124 			    _sd_cache_config.gen_pattern,
125 			    _sd_cache_config.fill_pattern,
126 			    _sd_cache_config.num_nodes);
127 		mdb_dec_indent(4);
128 	}
129 
130 	if (mdb_readvar(&_sd_net_config, "_sd_net_config") == -1) {
131 		mdb_warn("failed to read _sd_net_config symbol");
132 	} else {
133 		mdb_inc_indent(4);
134 		mdb_printf(
135 	"psize %4-d configured %d csize %10-d wsize %10-d cpages %6d\n",
136 			_sd_net_config.sn_psize,
137 			_sd_net_config.sn_configured,
138 			_sd_net_config.sn_csize,
139 			_sd_net_config.sn_wsize,
140 			_sd_net_config.sn_cpages);
141 
142 		mdb_dec_indent(4);
143 #ifdef SAFESTORE
144 		print_wrq(&(_sd_net_config.sn_wr_queue), FALSE);
145 #endif
146 	}
147 
148 
149 	if (mdb_readvar(&_sd_ft_data, "_sd_ft_data") == -1) {
150 		mdb_warn("failed to read _sd_ft_data symbol");
151 
152 	} else {
153 		mdb_printf("FT data:\n");
154 		mdb_inc_indent(4);
155 		mdb_printf("crashed %d host_state <%b> numio %d\n",
156 			_sd_ft_data.fi_crashed,
157 			_sd_ft_data.fi_host_state, host_states,
158 			_sd_ft_data.fi_numio);
159 		mdb_printf("lock %?-p (owner) rem_sv %h-x sleep %?-p (owner)\n",
160 			_sd_ft_data.fi_lock._opaque[0],
161 			_sd_ft_data.fi_rem_sv._opaque,
162 			_sd_ft_data.fi_sleep._opaque[0]);
163 		mdb_dec_indent(4);
164 	}
165 
166 	if (mdb_readvar(&_sd_node_hint, "_sd_node_hint") == -1) {
167 		mdb_warn("failed to read _sd_node_hint symbol");
168 
169 	} else
170 		mdb_printf("Node Hints: %08x <%b>\n",
171 			_sd_node_hint, cache_hints);
172 
173 	display_var("sdbc_wrthru_len", UINTTYPE);
174 	display_var("_sd_debug_level", UINTTYPE);
175 	display_var("_sdbc_attached", UINTTYPE);
176 
177 	return (DCMD_OK);
178 }
179 
180 static void
181 sdbc_hit_percent(uint_t hits, uint_t misses, char *type)
182 {
183 	uint64_t dhits, dmisses;
184 	uint64_t hit_rate = 0;
185 
186 	mdb_printf("%s hits: %u\t %s misses: %u\n", type, hits, type, misses);
187 
188 	/* a little crude. anything less than 1 percent will show as 0 */
189 	if (hits > 0 || misses > 0) {
190 		dhits = (uint64_t)hits;
191 		dmisses = (uint64_t)misses;
192 		hit_rate = (dhits * 100)/ (dhits + dmisses);
193 		mdb_printf("%s hit rate: %lld %%\n", type, hit_rate);
194 	}
195 	mdb_printf("\n");
196 }
197 
198 /*ARGSUSED*/
199 static int
200 sdbc_stats(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
201 {
202 	int i;
203 	char *fn;
204 	_sd_stats_t *_sd_cache_stats; /* local memory */
205 	uintptr_t _sd_cache_statsp; /* kernel pointer */
206 	_sd_shared_t *sh;
207 	int statssize;
208 	GElf_Sym sym;
209 	int maxdevs;
210 
211 	if (argc != 0)
212 		return (DCMD_USAGE);
213 
214 	/* get the number of volumes */
215 	if (mdb_readvar(&maxdevs, "sdbc_max_devs") == -1) {
216 		mdb_warn("failed to read  sdbc_max_devs");
217 		return (DCMD_ERR);
218 	}
219 
220 	statssize = sizeof (_sd_stats_t) + (maxdevs - 1) *
221 						sizeof (_sd_shared_t);
222 
223 	_sd_cache_stats = mdb_zalloc(statssize, UM_SLEEP);
224 
225 	if (mdb_lookup_by_obj("sdbc", "_sd_cache_stats", &sym) == -1) {
226 		mdb_warn("failed to lookup _sd_cache_stats symbol");
227 		return (DCMD_ERR);
228 	}
229 
230 	if (mdb_vread(&_sd_cache_statsp, sizeof (uintptr_t),
231 						sym.st_value) == -1) {
232 		mdb_warn("failed to read _sd_stats_t pointer");
233 		return (DCMD_ERR);
234 	}
235 
236 	if (mdb_vread(_sd_cache_stats, statssize, _sd_cache_statsp) == -1) {
237 		mdb_warn("failed to read _sd_stats_t structure");
238 		return (DCMD_ERR);
239 	}
240 
241 	mdb_printf("Storage Device Block Cache Statistics\n");
242 	mdb_printf("-------------------------------------\n");
243 
244 	i = _sd_cache_stats->st_blksize;
245 	mdb_printf("Blocksize: 0x%x (%d)\n", i, i);
246 
247 	mdb_printf("\n");
248 	sdbc_hit_percent(_sd_cache_stats->st_rdhits, _sd_cache_stats->st_rdmiss,
249 				"Read");
250 	sdbc_hit_percent(_sd_cache_stats->st_wrhits, _sd_cache_stats->st_wrmiss,
251 				"Write");
252 
253 	mdb_printf("%3s %10s %8s %8s %8s %8s %8s %7s %4s %4s %s\n",
254 		"Cd", "Dev", "Size",
255 		"CacheRd", "CacheWr", "DiskRd", "DiskWr",
256 		"DirtyBl", "#IO", "Fail", "F");
257 	for (i = 0; i < maxdevs; i++) {
258 		sh = &_sd_cache_stats->st_shared[i];
259 		if (!sh->sh_alloc)
260 			continue;
261 		fn = strrchr(sh->sh_filename, '/');
262 		fn = fn ? fn+1 : sh->sh_filename;
263 		mdb_printf("%3d %10s %7d %8d %8d %8d %8d %7d %4d %4d %d\n",
264 			sh->sh_cd, fn, sh->sh_filesize,
265 			sh->sh_cache_read, sh->sh_cache_write,
266 			sh->sh_disk_read, sh->sh_disk_write,
267 			sh->sh_numdirty, sh->sh_numio, sh->sh_numfail,
268 			sh->sh_failed);
269 	}
270 
271 	mdb_free(_sd_cache_stats, statssize);
272 	return (DCMD_OK);
273 }
274 
275 /*
276  * display some variables and counters
277  */
278 static void
279 display_var(char *name, enum vartype type)
280 {
281 	uint_t		uintval;
282 	uintptr_t	addrval;
283 	kmutex_t	lockval;
284 	kcondvar_t	cvval;
285 
286 	switch (type) {
287 		case UINTTYPE:
288 			if (mdb_readvar(&uintval, name) == -1) {
289 				mdb_warn("failed to read %s variable", name);
290 			} else
291 				mdb_printf("%s =\t%8x %12u\n",
292 						    name, uintval, uintval);
293 			break;
294 		case ADDRTYPE:
295 			if (mdb_readvar(&addrval, name) == -1) {
296 				mdb_warn("failed to read %s variable", name);
297 			} else
298 				mdb_printf("%s =\t%?-p\n",
299 						    name, addrval);
300 			break;
301 		case LOCKTYPE:
302 			if (mdb_readvar(&lockval, name) == -1) {
303 				mdb_warn("failed to read %s lock variable",
304 								name);
305 			} else
306 				mdb_printf("%s =\t%-p (owner)\n",
307 						name, lockval._opaque[0]);
308 			break;
309 		case CVTYPE:
310 			if (mdb_readvar(&cvval, name) == -1) {
311 				mdb_warn("failed to read %s condvar variable",
312 								name);
313 			} else
314 				mdb_printf("%s = \t%h-x\n",
315 						name, cvval._opaque);
316 			break;
317 		default:
318 			mdb_warn("display_var: unknown type");
319 	}
320 }
321 
322 mdb_bitmask_t dealloc_flag_vals[] = {
323 	{ "PROCESS_CACHE_DM", (u_longlong_t)~0, PROCESS_CACHE_DM },
324 	{ "CACHE_SHUTDOWN_DM", (u_longlong_t)~0, CACHE_SHUTDOWN_DM },
325 	{ "CACHE_THREAD_TERMINATED_DM",
326 	    (u_longlong_t)~0, CACHE_THREAD_TERMINATED_DM },
327 	{ "TIME_DELAY_LVL0", (u_longlong_t)~0, TIME_DELAY_LVL0 },
328 	{ "TIME_DELAY_LVL1", (u_longlong_t)~0, TIME_DELAY_LVL1 },
329 	{ "TIME_DELAY_LVL2", (u_longlong_t)~0, TIME_DELAY_LVL2 },
330 	{ NULL, 0, 0 }
331 };
332 
333 mdb_bitmask_t mdp_bits[] = {
334 	{ "MONITOR_DYNMEM_PROCESS_DEFAULT",
335 	    (u_longlong_t)~0, MONITOR_DYNMEM_PROCESS_DEFAULT},
336 	{ "RPT_SHUTDOWN_PROCESS_DM",
337 	    RPT_SHUTDOWN_PROCESS_DM, RPT_SHUTDOWN_PROCESS_DM },
338 	{ "RPT_DEALLOC_STATS1_DM",
339 	    RPT_DEALLOC_STATS1_DM, RPT_DEALLOC_STATS1_DM },
340 	{ "RPT_DEALLOC_STATS2_DM",
341 	    RPT_DEALLOC_STATS2_DM, RPT_DEALLOC_STATS2_DM },
342 	{ NULL, 0, 0 }
343 };
344 
345 mdb_bitmask_t process_directive_bits[] = {
346 	{ "PROCESS_DIRECTIVE_DEFAULT",
347 	    (u_longlong_t)~0, PROCESS_DIRECTIVE_DEFAULT },
348 	{ "WAKE_DEALLOC_THREAD_DM",
349 	    WAKE_DEALLOC_THREAD_DM, WAKE_DEALLOC_THREAD_DM },
350 	{ "MAX_OUT_ACCEL_HIST_FLAG_DM",
351 	    MAX_OUT_ACCEL_HIST_FLAG_DM, MAX_OUT_ACCEL_HIST_FLAG_DM},
352 	{ NULL, 0, 0 }
353 };
354 
355 /*ARGSUSED*/
356 static int
357 sdbc_vars(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
358 {
359 	int sd_dealloc_flag_dm;
360 	_dm_process_vars_t dynmem_processing_dm;
361 
362 	if (argc != 0)
363 		return (DCMD_USAGE);
364 
365 	mdb_printf("counters and other variables:\n");
366 	mdb_inc_indent(4);
367 
368 	display_var("xmem_inval_hit", UINTTYPE);
369 	display_var("xmem_inval_miss", UINTTYPE);
370 	display_var("xmem_inval_inuse", UINTTYPE);
371 
372 	display_var("sdbc_allocb_pageio1", UINTTYPE);
373 	display_var("sdbc_allocb_pageio2", UINTTYPE);
374 	display_var("sdbc_allocb_inuse", UINTTYPE);
375 	display_var("sdbc_allocb_hit", UINTTYPE);
376 	display_var("sdbc_allocb_lost", UINTTYPE);
377 	display_var("sdbc_pageio_always", UINTTYPE);
378 	display_var("sdbc_do_page", UINTTYPE);
379 	display_var("sdbc_flush_pageio", UINTTYPE);
380 
381 	display_var("sdbc_centry_hit", UINTTYPE);
382 	display_var("sdbc_centry_inuse", UINTTYPE);
383 	display_var("sdbc_centry_lost", UINTTYPE);
384 	display_var("sdbc_centry_deallocd", UINTTYPE);
385 
386 	display_var("_sd_prefetch_opt", UINTTYPE);
387 
388 	display_var("sdbc_ra_hash", UINTTYPE);
389 	display_var("sdbc_ra_none", UINTTYPE);
390 
391 	display_var("sdbc_static_cache", UINTTYPE);
392 	display_var("sdbc_use_dmchain", UINTTYPE);
393 
394 	/* in no particular order ... */
395 	display_var("sdbc_check_cot", UINTTYPE);
396 	display_var("_sd_cctl_groupsz", UINTTYPE);
397 	display_var("CBLOCKS", UINTTYPE);
398 	display_var("_SD_SELF_HOST", UINTTYPE);
399 	display_var("_SD_MIRROR_HOST", UINTTYPE);
400 	display_var("sdbc_bio_count", UINTTYPE);
401 	display_var("_sd_cblock_shift", UINTTYPE);
402 	display_var("_sd_nodes_configured", UINTTYPE);
403 	display_var("nv_alloc_factor", UINTTYPE);
404 	display_var("_sd_ft_exit", UINTTYPE);
405 	display_var("_sd_flush_exit", UINTTYPE);
406 	display_var("_sd_node_recovery", UINTTYPE);
407 	display_var("_sd_async_recovery", UINTTYPE);
408 	display_var("_sdbc_ft_hold_io", UINTTYPE);
409 	display_var("mirror_clean_shutdown", UINTTYPE);
410 	display_var("_sd_ft_warm_start", UINTTYPE);
411 	mdb_dec_indent(4);
412 	mdb_printf("\n");
413 
414 	/* some addresses of various lists and tables */
415 	mdb_printf("Addresses:\n");
416 	mdb_inc_indent(4);
417 	display_var("_sd_htable", ADDRTYPE);
418 	display_var("_sdbc_gl_centry_info", ADDRTYPE);
419 	display_var("_sdbc_gl_centry_info_nvmem", ADDRTYPE);
420 	display_var("_sdbc_gl_centry_info_size", ADDRTYPE); /* size_t */
421 	display_var("_sdbc_gl_file_info", ADDRTYPE);
422 	display_var("_sdbc_gl_file_info_size", ADDRTYPE); /* size_t */
423 	mdb_dec_indent(4);
424 	mdb_printf("\n");
425 
426 	/* dynamic memory variables */
427 	mdb_printf("Dynamic Memory variables and stats:\n");
428 	mdb_inc_indent(4);
429 	display_var("_sdbc_memtype_deconfigure_delayed", UINTTYPE);
430 
431 	if (mdb_readvar(&sd_dealloc_flag_dm, "sd_dealloc_flag_dm") == -1) {
432 		mdb_warn("failed to read sd_dealloc_flag_dm symbol");
433 	} else
434 		mdb_printf("sd_dealloc_flag_dm %08x <%b>\n",
435 				sd_dealloc_flag_dm,
436 				sd_dealloc_flag_dm, dealloc_flag_vals);
437 
438 	if (mdb_readvar(&dynmem_processing_dm, "dynmem_processing_dm") == -1) {
439 		mdb_warn("failed to read dynmem_processing_dm structure");
440 	} else {
441 		_dm_process_vars_t *dp;
442 
443 		dp = &dynmem_processing_dm;
444 
445 		mdb_printf(
446 		"thread_dm_cv %h-x thread_dm_lock %?-p (owner)\n",
447 			dp->thread_dm_cv._opaque,
448 			dp->thread_dm_lock._opaque[0]);
449 
450 		mdb_printf("sd_dealloc_flagx %x %8Tmax_dyn_list %3-d\n",
451 			dp->sd_dealloc_flagx,
452 			dp->max_dyn_list);
453 
454 		mdb_printf("monitor_dynmem_process <%b>\n",
455 			dp->monitor_dynmem_process, mdp_bits);
456 
457 		mdb_printf(
458 	"cache_aging_ct1 %3-d  %8Tcache_aging_ct2 %3-d cache_aging_ct3 %3-d\n",
459 			dp->cache_aging_ct1,
460 			dp->cache_aging_ct2,
461 			dp->cache_aging_ct3);
462 
463 		mdb_printf(
464 			"cache_aging_sec1 %3-d %8Tcache_aging_sec2 %3-d"
465 			" cache_aging_sec3 %3-d\n",
466 			dp->cache_aging_sec1,
467 			dp->cache_aging_sec2,
468 			dp->cache_aging_sec3);
469 
470 		mdb_printf("cache_aging_pcnt1 %3-d %8Tcache_aging_pcnt2 %3-d\n",
471 			dp->cache_aging_pcnt1,
472 			dp->cache_aging_pcnt2);
473 
474 		mdb_printf(
475 		    "max_holds_pcnt %3-d %8Talloc_ct %8-d dealloc_ct %8-d\n",
476 			dp->max_holds_pcnt,
477 			dp->alloc_ct,
478 			dp->dealloc_ct);
479 
480 		mdb_printf(
481 		"history %4x %8Tnodatas %8-d notavail %8-d candidates %8-d\n",
482 			dp->history,
483 			dp->nodatas,
484 			dp->notavail,
485 			dp->candidates);
486 
487 		mdb_printf(
488 			"deallocs %8-d %8Thosts %8-d pests %8-d metas %8-d\n",
489 			dp->deallocs,
490 			dp->hosts,
491 			dp->pests,
492 			dp->metas);
493 
494 		mdb_printf("holds %8-d %8Tothers %8-d\n",
495 			dp->holds,
496 			dp->others);
497 
498 		mdb_printf("process_directive <%b>\n",
499 			dp->process_directive, process_directive_bits);
500 
501 		mdb_printf("read_hits %8-d %8Tread_misses %8-d\n",
502 			dp->read_hits,
503 			dp->read_misses);
504 
505 		mdb_printf(
506 		    "write_thru %8-d %8Twrite_hits %8-d write_misses %8-d\n",
507 			dp->write_hits,
508 			dp->write_misses,
509 			dp->write_thru);
510 
511 		mdb_printf("prefetch_hits %8-d prefetch_misses %8-d\n",
512 			dp->prefetch_hits,
513 			dp->prefetch_misses);
514 	}
515 	mdb_dec_indent(4);
516 	mdb_printf("\n");
517 
518 	/* some locks and condition variables */
519 	mdb_printf("Locks:\n");
520 	mdb_inc_indent(4);
521 	display_var("mutex_and_condvar_flag", UINTTYPE);
522 	display_var("_sd_cache_lock", LOCKTYPE);
523 	display_var("_sd_block_lk", LOCKTYPE);
524 	display_var("_sdbc_config_lock", LOCKTYPE);
525 	display_var("_sdbc_ft_hold_io_lk", LOCKTYPE);
526 	display_var("_sd_flush_cv", CVTYPE);
527 	display_var("_sdbc_ft_hold_io_cv", CVTYPE);
528 	mdb_dec_indent(4);
529 	mdb_printf("\n");
530 
531 	return (DCMD_OK);
532 }
533 
534 const mdb_bitmask_t nsc_buf_bits[] = {
535 	{"HALLOCATED", NSC_HALLOCATED, NSC_HALLOCATED},
536 	{"HACTIVE", NSC_HACTIVE, NSC_HACTIVE},
537 	{"RDBUF", NSC_RDBUF, NSC_RDBUF},
538 	{"WRBUF", NSC_WRBUF, NSC_WRBUF},
539 	{"NOBLOCK", NSC_NOBLOCK, NSC_NOBLOCK},
540 	{"WRTHRU", NSC_WRTHRU, NSC_WRTHRU},
541 	{"NOCACHE", NSC_NOCACHE, NSC_NOCACHE},
542 	{"BCOPY", NSC_BCOPY, NSC_BCOPY},
543 	{"PAGEIO", NSC_PAGEIO, NSC_PAGEIO},
544 	{"PINNABLE", NSC_PINNABLE, NSC_PINNABLE},
545 	{"FORCED_WRTHRU", NSC_FORCED_WRTHRU, NSC_FORCED_WRTHRU},
546 	{"METADATA", NSC_METADATA, NSC_METADATA},
547 	{"MIXED", NSC_MIXED, NSC_MIXED},
548 	{NULL, 0, 0}
549 };
550 
551 
552 /*
553  * HELP functions for cache ctl type dcmds
554  */
555 
556 static void
557 cctl_help_common(char *name)
558 {
559 	mdb_inc_indent(4);
560 	mdb_printf("-c cd displays cctls for cache descriptor 'cd'\n");
561 	mdb_dec_indent(4);
562 	mdb_printf("inclusive filters:\n");
563 	mdb_inc_indent(4);
564 	mdb_printf("-b blk displays cctls for cache block number 'blk'\n");
565 	mdb_printf("-d displays cctls with dirty bits\n");
566 	mdb_printf("-h displays cctls that are hashed\n");
567 	mdb_printf("-i displays cctls that are inuse\n");
568 	mdb_printf("-o displays cctls that have I/O in progress\n");
569 	mdb_printf("-p displays cctls that have pagio set\n");
570 	mdb_printf("-B displays cctls that are marked BAD\n");
571 	mdb_printf("-H displays cctls that are HOSTS\n");
572 	mdb_printf("-P displays cctls that are PARASITES\n");
573 	mdb_printf("-R displays cctls that are explicit (NSC_RDAHEAD) "
574 			"Prefetch bufs\n");
575 	mdb_printf("-r displays cctls that are implicit Prefetch bufs\n");
576 	mdb_printf("-V displays cctls that have valid bits set\n");
577 	mdb_printf("-v verbose\n");
578 	mdb_dec_indent(4);
579 
580 	mdb_printf("Default: %s displays all cctls in the list\n", name);
581 	mdb_printf("\n");
582 
583 	mdb_printf("Example:\n");
584 	mdb_inc_indent(4);
585 
586 	mdb_printf("%s -io -c 5 displays all cctls for cd 5 that are\n"
587 			"in use or have I/O in progress\n", name);
588 	mdb_dec_indent(4);
589 }
590 
591 #define	CCTL_OPTIONSTRING "[-vdhiopBHPV][-c cd][-b blknum]"
592 void
593 cctl_help()
594 {
595 	mdb_printf("sdbc_cctl displays cache ctl structures\n");
596 	mdb_printf("Usage: [address]::sdbc_cctl " CCTL_OPTIONSTRING "\n");
597 	cctl_help_common("sdbc_cctl");
598 }
599 
600 void
601 cchain_help()
602 {
603 	mdb_printf("sdbc_cchain displays cache ctl structures in a"
604 			" (alloc) cc_chain\n");
605 	mdb_printf("Usage: address::sdbc_cchain " CCTL_OPTIONSTRING "\n");
606 	cctl_help_common("sdbc_cchain");
607 }
608 
609 void
610 dchain_help()
611 {
612 	mdb_printf("sdbc_dchain displays cache ctl structures in a"
613 			" dirty chain\n");
614 	mdb_printf("Usage: address::sdbc_dchain " CCTL_OPTIONSTRING "\n");
615 	cctl_help_common("sdbc_dchain");
616 }
617 
618 void
619 dmchain_help()
620 {
621 	mdb_printf("sdbc_dmchain displays cache ctl structures in a"
622 			" dynamic memory allocation chain\n");
623 	mdb_printf("order of display is:\n"
624 		    "the cctl represented by the given address,\n"
625 		    "the cc_head_dm cctl,\n"
626 		    "the chain starting at cc_next_dm of the head cctl\n");
627 	mdb_printf("Usage: address::sdbc_dmchain " CCTL_OPTIONSTRING "\n");
628 	cctl_help_common("sdbc_dmchain");
629 }
630 
631 void
632 hashchain_help()
633 {
634 	mdb_printf("sdbc_hashchain displays cache ctl structures in a"
635 			" hash chain\n");
636 	mdb_printf("Usage: address::sdbc_hashchain " CCTL_OPTIONSTRING "\n");
637 	cctl_help_common("sdbc_hashchain");
638 }
639 
640 void
641 hashtable_help()
642 {
643 	mdb_printf("sdbc_hashtable displays the hash table and its chains\n");
644 	mdb_printf("Usage: address::sdbc_hashtable " CCTL_OPTIONSTRING "\n");
645 	cctl_help_common("sdbc_hashtable");
646 }
647 
648 
649 void
650 lru_help()
651 {
652 	mdb_printf("sdbc_lru displays cache ctl structures in the LRU queue\n");
653 	mdb_printf("Usage: [address]::sdbc_lru " CCTL_OPTIONSTRING "\n");
654 	cctl_help_common("sdbc_lru");
655 }
656 
657 /*
658  * help functions for write ctl dcmds
659  */
660 void
661 wctl_help_common(char *name)
662 {
663 	mdb_inc_indent(4);
664 	mdb_printf("-v verbose\n");
665 	mdb_printf("-c cd show ctl structs for cache descriptor 'cd'\n");
666 	mdb_printf("-d show ctl structs that have dirty bits set\n");
667 	mdb_dec_indent(4);
668 	mdb_printf("Default: %s displays all write ctl in the list\n", name);
669 }
670 
671 void
672 wctl_help()
673 {
674 	mdb_printf(
675 	    "sdbc_wctl displays the allocated array of write ctl structures\n");
676 	mdb_printf("Usage: [address]::sdbc_wctl [-vd][-c cd]\n");
677 	wctl_help_common("sdbc_wctl");
678 }
679 
680 void
681 wrq_help()
682 {
683 	mdb_printf("sdbc_wrq displays the write ctl queue (wctl free list)\n");
684 	mdb_printf("Usage: [address]::sdbc_wrq [-vd][-c cd]\n");
685 	wctl_help_common("sdbc_wrq");
686 }
687 
688 /* help function for the sdbc_cdinfo dcmd */
689 void
690 cdinfo_help()
691 {
692 	mdb_printf(
693 	"sdbc_cdinfo displays cd information from the _sd_cache_files table\n");
694 	mdb_printf("Usage: [address]::sdbc_cdfinfo [-av][-c cd]\n");
695 	mdb_inc_indent(4);
696 	mdb_printf("-a displays info for all cd_info structures\n");
697 	mdb_printf("-c cd displays info for cache descriptor 'cd'\n");
698 	mdb_printf("-v verbose\n");
699 	mdb_dec_indent(4);
700 	mdb_printf("Default: display info for cd's that are allocated\n");
701 }
702 
703 void
704 ftctl_help()
705 {
706 	mdb_printf(
707 	    "sdbc_ftctl displays the array of fault tolerant structures \n");
708 	mdb_printf("Usage: [address]::sdbc_ftctl [-vd][-c cd]\n");
709 	wctl_help_common("sdbc_ftctl");
710 }
711 
712 /*
713  * help function for the sdbc_handles dcmd
714  */
715 void
716 handle_help()
717 {
718 	mdb_printf("sdbc_handles displays active or allocated"
719 			" cache buffer handles\n");
720 	mdb_printf("Usage: [address]::sdbc_handles [-avC][-c cd]\n");
721 	mdb_inc_indent(4);
722 	mdb_printf("-a displays all handles\n");
723 	mdb_printf("-c n displays handle for cd n\n");
724 	mdb_printf("-v displays detailed handle data\n");
725 	mdb_printf("-C displays the handle cc_chain\n");
726 	mdb_dec_indent(4);
727 	mdb_printf("Default: display only allocated or active handles\n");
728 }
729 
730 /*
731  * help functions for the "global" memory dcmds
732  */
733 void
734 glcinfo_help()
735 {
736 	mdb_printf("sdbc_glcinfo displays the global cache entry info\n");
737 	mdb_printf("Usage: [address]::sdbc_glcinfo [-adC][-c cd][-b fbapos]\n");
738 	mdb_inc_indent(4);
739 	mdb_printf("-a displays all global info structs\n");
740 	mdb_printf("-b fbapos displays structs that match FBA block"
741 			"(not cache block) 'fbapos'\n");
742 	mdb_printf("-c cd displays structs that match cache descriptor 'cd'\n");
743 	mdb_printf("-d displays structs with dirty bits set\n");
744 	mdb_printf("-C does consistency check against nvram copy\n");
745 	mdb_dec_indent(4);
746 	mdb_printf("Default: display entries with a valid cd\n");
747 }
748 
749 void
750 glfinfo_help()
751 {
752 	mdb_printf("sdbc_glfinfo displays the global file info\n");
753 	mdb_printf("Usage: [address]::sdbc_glfinfo [-aptC]\n");
754 	mdb_inc_indent(4);
755 	mdb_printf("-a displays all global info structs\n");
756 	mdb_printf("-p displays structs for pinned volumes\n");
757 	mdb_printf("-t displays structs for attached volumes\n");
758 	mdb_printf("-C does consistency check against nvram copy\n");
759 	mdb_dec_indent(4);
760 	mdb_printf("Default: display entries with non-null filename\n");
761 }
762 
763 
764 /*
765  * WALKERS
766  */
767 
768 /*
769  * walker for the cctl list using the cc_link_list_dm pointers
770  */
771 static int
772 sdbc_cctl_winit(mdb_walk_state_t *wsp)
773 {
774 	_sd_cctl_t *_sd_cctl[_SD_CCTL_GROUPS]; /* for getting first entry */
775 	struct walk_info *winfo;
776 
777 	winfo = mdb_zalloc(sizeof (struct walk_info), UM_SLEEP);
778 
779 	if (wsp->walk_addr == NULL) {
780 		/*
781 		 * we get the "first" cctl from memory and then traverse
782 		 * the cc_link_list_dm pointers.
783 		 * this traversal could start from any cctl.  here we start with
784 		 * the first cctl in the _sd_cctl[] array.
785 		 */
786 		if (mdb_readvar(_sd_cctl, "_sd_cctl") == -1) {
787 			mdb_warn("failed to read _sd_cctl array");
788 			return (DCMD_ERR);
789 		}
790 
791 		wsp->walk_addr = (uintptr_t)_sd_cctl[0];
792 	}
793 
794 	winfo->w_start = 0;
795 	winfo->w_end = wsp->walk_addr;
796 	wsp->walk_data = winfo;
797 
798 	return (WALK_NEXT);
799 }
800 
801 static int
802 sdbc_cctl_wstep(mdb_walk_state_t *wsp)
803 {
804 	struct walk_info *winfo = wsp->walk_data;
805 	_sd_cctl_t centry;
806 	int status;
807 
808 	if (wsp->walk_addr == NULL) /* should not happen */
809 		return (WALK_DONE);
810 
811 	/*
812 	 * w_start is 0 on the first iteration so the test
813 	 * will fail, allowing the first centry to be processed
814 	 */
815 	if (wsp->walk_addr == winfo->w_start)
816 		return (WALK_DONE);
817 
818 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
819 		wsp->walk_cbdata);
820 
821 	if (mdb_vread(&centry, sizeof (_sd_cctl_t), wsp->walk_addr) == -1) {
822 		mdb_warn("failed to read centry at %p", wsp->walk_addr);
823 		return (WALK_ERR);
824 	}
825 	wsp->walk_addr = (uintptr_t)(centry.cc_link_list_dm);
826 	/* set termination condition. only needs to be done once */
827 	winfo->w_start = winfo->w_end;
828 
829 	return (status);
830 }
831 
832 static void
833 sdbc_cctl_wfini(mdb_walk_state_t *wsp)
834 {
835 	mdb_free(wsp->walk_data, sizeof (struct walk_info));
836 }
837 
838 /*
839  * walk the cc_chain list of a _sd_cctl_t
840  * no global walks -- must be called with an address
841  */
842 static int
843 sdbc_cchain_winit(mdb_walk_state_t *wsp)
844 {
845 	if (wsp->walk_addr == NULL)
846 		return (WALK_ERR);
847 
848 	wsp->walk_data = mdb_zalloc(sizeof (_sd_cctl_t), UM_SLEEP);
849 
850 	return (WALK_NEXT);
851 }
852 
853 static int
854 sdbc_cchain_wstep(mdb_walk_state_t *wsp)
855 {
856 	int status;
857 
858 	if (wsp->walk_addr == NULL)
859 		return (WALK_DONE);
860 
861 	if (mdb_vread(wsp->walk_data, sizeof (_sd_cctl_t), wsp->walk_addr)
862 				== -1) {
863 		mdb_warn("sdbc_cchain_wstep failed to read centry at %p",
864 			wsp->walk_addr);
865 		return (WALK_ERR);
866 	}
867 
868 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
869 						wsp->walk_cbdata);
870 
871 	wsp->walk_addr = (uintptr_t)(((_sd_cctl_t *)
872 				(wsp->walk_data))->cc_chain);
873 	return (status);
874 }
875 
876 static void
877 sdbc_cchain_wfini(mdb_walk_state_t *wsp)
878 {
879 	mdb_free(wsp->walk_data, sizeof (_sd_cctl_t));
880 }
881 
882 
883 /*
884  * walk the dirty chain list of a _sd_cctl_t
885  * no global walks -- must be called with an address
886  */
887 static int
888 sdbc_dchain_winit(mdb_walk_state_t *wsp)
889 {
890 	if (wsp->walk_addr == NULL)
891 		return (WALK_ERR);
892 
893 	wsp->walk_data = mdb_zalloc(sizeof (_sd_cctl_t), UM_SLEEP);
894 
895 	/* walk data stores the first and subsequent cc_dirty_link */
896 	if (mdb_vread(wsp->walk_data, sizeof (_sd_cctl_t), wsp->walk_addr)
897 				== -1) {
898 		mdb_warn("sdbc_dchain_winit failed to read centry at %p",
899 			wsp->walk_addr);
900 		return (WALK_ERR);
901 	}
902 
903 	return (WALK_NEXT);
904 }
905 
906 static int
907 sdbc_dchain_wstep(mdb_walk_state_t *wsp)
908 {
909 	_sd_cctl_t centry;
910 	int status;
911 
912 	if (wsp->walk_addr == NULL)
913 		return (WALK_DONE);
914 
915 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
916 						wsp->walk_cbdata);
917 
918 
919 	if (mdb_vread(&centry, sizeof (_sd_cctl_t), wsp->walk_addr)
920 				== -1) {
921 		mdb_warn("sdbc_dchain_wstep failed to read centry at %p",
922 			wsp->walk_addr);
923 		return (WALK_ERR);
924 	}
925 
926 	wsp->walk_addr =
927 		(uintptr_t)(centry.cc_dirty_next);
928 
929 	/* end of dirty_next chain?  start on subsequent dirty_link */
930 	if (wsp->walk_addr == NULL) {
931 		wsp->walk_addr =
932 		(uintptr_t)(((_sd_cctl_t *)(wsp->walk_data))->cc_dirty_link);
933 
934 		/* update dirty link */
935 		/* walk data stores the first and subsequent cc_dirty_link */
936 		if (wsp->walk_addr) {
937 			if (mdb_vread(wsp->walk_data, sizeof (_sd_cctl_t),
938 					wsp->walk_addr) == -1) {
939 
940 				mdb_warn(
941 				"sdbc_dchain_wstep failed to read centry at %p",
942 					wsp->walk_addr);
943 
944 				return (WALK_ERR);
945 			}
946 		}
947 	}
948 
949 	return (status);
950 }
951 
952 static void
953 sdbc_dchain_wfini(mdb_walk_state_t *wsp)
954 {
955 	mdb_free(wsp->walk_data, sizeof (_sd_cctl_t));
956 }
957 
958 /* for stepping thru the dynmem chain */
959 #define	GET_HEAD_DM 0x1
960 #define	GET_NEXT_DM 0x2
961 
962 /*
963  * walk the dm chain of a cctl
964  * start with current address, then cc_head_dm, then the cc_next_dm chain
965  */
966 static int
967 sdbc_dmchain_winit(mdb_walk_state_t *wsp)
968 {
969 	if (wsp->walk_addr == NULL)
970 		return (WALK_ERR);
971 
972 	wsp->walk_data = (void *)GET_HEAD_DM;
973 
974 	return (WALK_NEXT);
975 }
976 
977 static int
978 sdbc_dmchain_wstep(mdb_walk_state_t *wsp)
979 {
980 	_sd_cctl_t centry;
981 	int status;
982 
983 	if (wsp->walk_addr == NULL)
984 		return (WALK_DONE);
985 
986 	if (mdb_vread(&centry, sizeof (_sd_cctl_t), wsp->walk_addr)
987 				== -1) {
988 		mdb_warn("sdbc_dmchain_wstep failed to read centry at %p",
989 			wsp->walk_addr);
990 		return (WALK_ERR);
991 	}
992 
993 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
994 						wsp->walk_cbdata);
995 
996 	if (wsp->walk_data == (void *)GET_HEAD_DM) {
997 		wsp->walk_addr = (uintptr_t)centry.cc_head_dm;
998 		wsp->walk_data = (void *)GET_NEXT_DM;
999 	} else
1000 		wsp->walk_addr = (uintptr_t)centry.cc_next_dm;
1001 
1002 	return (status);
1003 }
1004 
1005 /*ARGSUSED*/
1006 static void
1007 sdbc_dmchain_wfini(mdb_walk_state_t *wsp)
1008 {
1009 }
1010 
1011 /*
1012  * walk a hash chain
1013  * requires an address
1014  */
1015 /*ARGSUSED*/
1016 static int
1017 sdbc_hashchain_winit(mdb_walk_state_t *wsp)
1018 {
1019 
1020 	if (wsp->walk_addr == NULL)
1021 		return (WALK_ERR);
1022 
1023 
1024 	return (WALK_NEXT);
1025 }
1026 
1027 static int
1028 sdbc_hashchain_wstep(mdb_walk_state_t *wsp)
1029 {
1030 	int status;
1031 	_sd_hash_hd_t hash_entry;
1032 
1033 
1034 	if (wsp->walk_addr == NULL)
1035 		return (WALK_DONE);
1036 
1037 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
1038 						wsp->walk_cbdata);
1039 
1040 	if (mdb_vread(&hash_entry, sizeof (_sd_hash_hd_t),
1041 					wsp->walk_addr) == -1) {
1042 		mdb_warn(
1043 			"sdbc_hashchain_wstep failed to read hash_entry at %p",
1044 			wsp->walk_addr);
1045 		return (WALK_ERR); /* will upper layer continue ? */
1046 	}
1047 
1048 	wsp->walk_addr = (uintptr_t)hash_entry.hh_next;
1049 
1050 	return (status);
1051 }
1052 
1053 /*ARGSUSED*/
1054 static void
1055 sdbc_hashchain_wfini(mdb_walk_state_t *wsp)
1056 {
1057 }
1058 
1059 /*
1060  * walk the sdbc lru list
1061  */
1062 static int
1063 sdbc_lru_winit(mdb_walk_state_t *wsp)
1064 {
1065 	struct walk_info *winfo;
1066 	GElf_Sym sym;
1067 
1068 	winfo = mdb_zalloc(sizeof (struct walk_info), UM_SLEEP);
1069 
1070 	/* if called without an address, start at the head of the queue */
1071 	if (wsp->walk_addr == NULL) {
1072 
1073 		if (mdb_lookup_by_obj("sdbc", "_sd_lru_q", &sym) == -1) {
1074 			mdb_warn("failed to lookup _sd_lru_q symbol");
1075 			return (WALK_ERR);
1076 		}
1077 
1078 		/* &(_sd_lru_q.sq_qhead) */
1079 		wsp->walk_addr = (uintptr_t)(sym.st_value);
1080 	}
1081 
1082 	winfo->w_start = 0;
1083 	winfo->w_end = wsp->walk_addr;
1084 	wsp->walk_data = winfo;
1085 
1086 	return (WALK_NEXT);
1087 }
1088 
1089 static int
1090 sdbc_lru_wstep(mdb_walk_state_t *wsp)
1091 {
1092 	struct walk_info *winfo = wsp->walk_data;
1093 	_sd_cctl_t centry;
1094 	int status;
1095 
1096 	if (wsp->walk_addr == NULL) /* should not happen */
1097 		return (WALK_DONE);
1098 
1099 	/*
1100 	 * w_start is 0 on the first iteration so the test
1101 	 * will fail, allowing the first centry to be processed
1102 	 */
1103 	if (wsp->walk_addr == winfo->w_start)
1104 		return (WALK_DONE);
1105 
1106 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
1107 						wsp->walk_cbdata);
1108 
1109 	if (mdb_vread(&centry, sizeof (_sd_cctl_t), wsp->walk_addr) == -1) {
1110 		mdb_warn("failed to read centry at %p", wsp->walk_addr);
1111 		return (WALK_ERR);
1112 	}
1113 	wsp->walk_addr = (uintptr_t)(centry.cc_next);
1114 
1115 	/* set termination condition. only needs to be done once */
1116 	winfo->w_start = winfo->w_end;
1117 
1118 	return (status);
1119 }
1120 
1121 static void
1122 sdbc_lru_wfini(mdb_walk_state_t *wsp)
1123 {
1124 	mdb_free(wsp->walk_data, sizeof (struct walk_info));
1125 }
1126 
1127 
1128 #ifdef SAFESTORE
1129 /*
1130  * walk the array of allocated write control structures
1131  */
1132 
1133 static int
1134 sdbc_wctl_winit(mdb_walk_state_t *wsp)
1135 {
1136 	_sd_net_t  _sd_net_config;
1137 	_sd_writeq_t wrq;
1138 	struct walk_info *winfo;
1139 	int blk_shft;
1140 	int count;
1141 
1142 
1143 	winfo = mdb_zalloc(sizeof (struct walk_info), UM_SLEEP);
1144 
1145 	/* need to calculate the end of the array */
1146 	if (mdb_readvar(&_sd_net_config, "_sd_net_config") == -1) {
1147 		mdb_warn("failed to read _sd_net_config structure");
1148 		return (WALK_ERR);
1149 	}
1150 
1151 	if (wsp->walk_addr == NULL)
1152 		wsp->walk_addr = (uintptr_t)(_sd_net_config.sn_wr_cctl);
1153 
1154 	/*
1155 	 * this module assumes 8k block size so this code can
1156 	 * be commented out if necessary.
1157 	 */
1158 	if (mdb_readvar(&blk_shft, "_sd_cblock_shift") == -1) {
1159 		mdb_warn("failed to read _sd_cblock_shift."
1160 			"assuming 8k cache block size");
1161 		blk_shft = 13;
1162 	}
1163 
1164 	count = (_sd_net_config.sn_wpages * _sd_net_config.sn_psize) /
1165 						    (1 << blk_shft);
1166 
1167 	winfo->w_end = (uintptr_t)(_sd_net_config.sn_wr_cctl + count);
1168 	wsp->walk_data = winfo;
1169 
1170 	return (WALK_NEXT);
1171 }
1172 
1173 static int
1174 sdbc_wctl_wstep(mdb_walk_state_t *wsp)
1175 {
1176 	struct walk_info *winfo = wsp->walk_data;
1177 	int status;
1178 
1179 	if (wsp->walk_addr == NULL)
1180 		return (WALK_DONE);
1181 
1182 	if (wsp->walk_addr >= winfo->w_end)
1183 		return (WALK_DONE);
1184 
1185 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
1186 						wsp->walk_cbdata);
1187 
1188 	wsp->walk_addr += sizeof (_sd_wr_cctl_t);
1189 
1190 	return (status);
1191 
1192 }
1193 
1194 static void
1195 sdbc_wctl_wfini(mdb_walk_state_t *wsp)
1196 {
1197 	mdb_free(wsp->walk_data, sizeof (struct walk_info));
1198 }
1199 
1200 /*
1201  * walk the queue (free list) of write control structures
1202  */
1203 
1204 static int
1205 sdbc_wrq_winit(mdb_walk_state_t *wsp)
1206 {
1207 	_sd_net_t  _sd_net_config;
1208 	_sd_writeq_t wrq;
1209 
1210 	/* if called without an address, start at the head of the queue */
1211 	if (wsp->walk_addr == NULL) {
1212 
1213 		if (mdb_readvar(&_sd_net_config, "_sd_net_config") == -1) {
1214 			mdb_warn("failed to read _sd_net_config structure");
1215 			return (WALK_ERR);
1216 		}
1217 
1218 		wsp->walk_addr = (uintptr_t)
1219 					(_sd_net_config.sn_wr_queue.wq_qtop);
1220 	}
1221 
1222 	return (WALK_NEXT);
1223 }
1224 
1225 static int
1226 sdbc_wrq_wstep(mdb_walk_state_t *wsp)
1227 {
1228 	_sd_wr_cctl_t wctl;
1229 	int status;
1230 
1231 	if (wsp->walk_addr == NULL)
1232 		return (WALK_DONE);
1233 
1234 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
1235 						wsp->walk_cbdata);
1236 
1237 	if (mdb_vread(&wctl, sizeof (_sd_wr_cctl_t), wsp->walk_addr)
1238 				== -1) {
1239 		mdb_warn("sdbc_cchain_wstep failed to read wctl at %p",
1240 			wsp->walk_addr);
1241 		return (WALK_ERR);
1242 	}
1243 
1244 	/* special case -- mini-DSP fake wr_cctl */
1245 	if (wsp->walk_addr == (uintptr_t)wctl.wc_next)
1246 		return (WALK_DONE);
1247 
1248 	wsp->walk_addr = (uintptr_t)(wctl.wc_next);
1249 
1250 	return (WALK_NEXT);
1251 }
1252 
1253 static void
1254 sdbc_wrq_wfini(mdb_walk_state_t *wsp)
1255 {
1256 }
1257 #endif /* SAFESTORE */
1258 /*
1259  * walk the _sd_cache_files array of cd_info structures
1260  */
1261 static int
1262 sdbc_cdinfo_winit(mdb_walk_state_t *wsp)
1263 {
1264 	struct walk_info *winfo;
1265 	_sd_cd_info_t	*_sd_cache_files_addr;
1266 	int maxdevs;
1267 
1268 	winfo = mdb_zalloc(sizeof (struct walk_info), UM_SLEEP);
1269 
1270 
1271 	/* get the address of the cdinfo table */
1272 	if (mdb_readvar(&_sd_cache_files_addr, "_sd_cache_files") == -1) {
1273 		mdb_warn("failed to read _sd_cache_files address\n");
1274 		return (WALK_ERR);
1275 	}
1276 
1277 	/* if called without an address, start at the head of the queue */
1278 	if (wsp->walk_addr == NULL) {
1279 		/* address of first _sd_cd_info_t */
1280 		wsp->walk_addr = (uintptr_t)(_sd_cache_files_addr);
1281 	}
1282 
1283 	/* get the number of volumes */
1284 	if (mdb_readvar(&maxdevs, "sdbc_max_devs") == -1) {
1285 		mdb_warn("failed to read  sdbc_max_devs");
1286 		return (WALK_ERR);
1287 	}
1288 
1289 	winfo->w_end = (uintptr_t)(_sd_cache_files_addr + maxdevs);
1290 	wsp->walk_data = winfo;
1291 
1292 	return (WALK_NEXT);
1293 }
1294 
1295 static int
1296 sdbc_cdinfo_wstep(mdb_walk_state_t *wsp)
1297 {
1298 	struct walk_info *winfo = wsp->walk_data;
1299 	int status;
1300 
1301 	if (wsp->walk_addr >= winfo->w_end)
1302 		return (WALK_DONE);
1303 
1304 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
1305 						wsp->walk_cbdata);
1306 
1307 	wsp->walk_addr += sizeof (_sd_cd_info_t);
1308 
1309 	return (status);
1310 }
1311 
1312 static void
1313 sdbc_cdinfo_wfini(mdb_walk_state_t *wsp)
1314 {
1315 	mdb_free(wsp->walk_data, sizeof (struct walk_info));
1316 }
1317 
1318 #ifdef SAFESTORE
1319 /*
1320  * walk the array of allocated fault tolerant control structures
1321  */
1322 static int
1323 sdbc_ftctl_winit(mdb_walk_state_t *wsp)
1324 {
1325 	_sd_net_t  _sd_net_config;
1326 	struct walk_info *winfo;
1327 	int blk_shft = 13; /* 8k default */
1328 	int count;
1329 
1330 
1331 	winfo = mdb_zalloc(sizeof (struct walk_info), UM_SLEEP);
1332 
1333 	/* need to calculate the end of the array */
1334 	if (mdb_readvar(&_sd_net_config, "_sd_net_config") == -1) {
1335 		mdb_warn("failed to read _sd_net_config structure");
1336 		return (WALK_ERR);
1337 	}
1338 
1339 	if (wsp->walk_addr == NULL)
1340 		wsp->walk_addr = (uintptr_t)(_sd_net_config.sn_ft_cctl);
1341 
1342 	/*
1343 	 * this module assumes 8k block size so this code can
1344 	 * be commented out if necessary.
1345 	 */
1346 	if (mdb_readvar(&blk_shft, "_sd_cblock_shift") == -1) {
1347 		mdb_warn("failed to read _sd_cblock_shift."
1348 			"assuming 8k cache block size");
1349 		blk_shft = 13;
1350 	}
1351 
1352 	count = (_sd_net_config.sn_wpages * _sd_net_config.sn_psize) /
1353 						    (1 << blk_shft);
1354 
1355 	winfo->w_end = (uintptr_t)(_sd_net_config.sn_ft_cctl + count);
1356 	wsp->walk_data = winfo;
1357 
1358 	return (WALK_NEXT);
1359 }
1360 
1361 static int
1362 sdbc_ftctl_wstep(mdb_walk_state_t *wsp)
1363 {
1364 	struct walk_info *winfo = wsp->walk_data;
1365 	int status;
1366 
1367 	if (wsp->walk_addr == NULL)
1368 		return (WALK_DONE);
1369 
1370 	if (wsp->walk_addr >= winfo->w_end)
1371 		return (WALK_DONE);
1372 
1373 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
1374 						wsp->walk_cbdata);
1375 
1376 	wsp->walk_addr += sizeof (_sd_ft_cctl_t);
1377 
1378 	return (status);
1379 }
1380 
1381 static void
1382 sdbc_ftctl_wfini(mdb_walk_state_t *wsp)
1383 {
1384 	mdb_free(wsp->walk_data, sizeof (struct walk_info));
1385 }
1386 #endif /* SAFESTORE */
1387 
1388 /*
1389  * walk the handle list
1390  */
1391 static int
1392 sdbc_handle_winit(mdb_walk_state_t *wsp)
1393 {
1394 	_sd_buf_hlist_t hl;
1395 	struct walk_info *winfo;
1396 	GElf_Sym sym;
1397 
1398 	if (mdb_readvar(&hl, "_sd_handle_list") == -1) {
1399 		mdb_warn("failed to read _sd_handle_list structure");
1400 		return (WALK_ERR);
1401 	}
1402 
1403 	if (mdb_lookup_by_obj("sdbc", "_sd_handle_list", &sym) == -1) {
1404 		mdb_warn("failed to lookup _sd_handle_list symbol");
1405 		return (WALK_ERR);
1406 	}
1407 
1408 	/* if called without an address, start at first element in list */
1409 	if (wsp->walk_addr == NULL)
1410 		wsp->walk_addr = (uintptr_t)(hl.hl_top.bh_next);
1411 
1412 	winfo = mdb_zalloc(sizeof (struct walk_info), UM_SLEEP);
1413 
1414 	winfo->w_end = (uintptr_t)(sym.st_value); /* &_sd_handle_list.hl_top */
1415 	wsp->walk_data = winfo;
1416 
1417 	return (WALK_NEXT);
1418 }
1419 
1420 static int
1421 sdbc_handle_wstep(mdb_walk_state_t *wsp)
1422 {
1423 	struct walk_info *winfo = wsp->walk_data;
1424 	_sd_buf_handle_t handle;
1425 	int status;
1426 
1427 	if (wsp->walk_addr == NULL)
1428 		return (WALK_DONE);
1429 
1430 	if (wsp->walk_addr == winfo->w_end)
1431 		return (WALK_DONE);
1432 
1433 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
1434 						wsp->walk_cbdata);
1435 
1436 	if (mdb_vread(&handle, sizeof (_sd_buf_handle_t), wsp->walk_addr)
1437 								== -1) {
1438 		mdb_warn("failed to read handle at %p", wsp->walk_addr);
1439 		return (WALK_ERR);
1440 	}
1441 
1442 	wsp->walk_addr = (uintptr_t)(handle.bh_next);
1443 
1444 	return (status);
1445 }
1446 
1447 static void
1448 sdbc_handle_wfini(mdb_walk_state_t *wsp)
1449 {
1450 	mdb_free(wsp->walk_data, sizeof (struct walk_info));
1451 }
1452 
1453 /*
1454  * walk the global info array (dirty bits)
1455  */
1456 
1457 static int
1458 sdbc_glcinfo_winit(mdb_walk_state_t *wsp)
1459 {
1460 	ss_centry_info_t *gl_centry_info;
1461 	size_t gl_centry_info_size;
1462 	struct walk_info *winfo;
1463 
1464 
1465 	winfo = mdb_zalloc(sizeof (struct walk_info), UM_SLEEP);
1466 
1467 	/* get start of the cache entry metadata */
1468 	if (mdb_readvar(&gl_centry_info, "_sdbc_gl_centry_info") == -1) {
1469 		mdb_warn("failed to read  _sdbc_gl_centry_info");
1470 		return (WALK_ERR);
1471 	}
1472 
1473 	/* need to calculate the end of the array */
1474 	if (mdb_readvar(&gl_centry_info_size,
1475 				"_sdbc_gl_centry_info_size") == -1) {
1476 		mdb_warn("failed to read  _sdbc_gl_centry_info_size");
1477 		return (WALK_ERR);
1478 	}
1479 
1480 	if (wsp->walk_addr == NULL)
1481 		wsp->walk_addr = (uintptr_t)(gl_centry_info);
1482 
1483 
1484 
1485 	winfo->w_end = ((uintptr_t)(gl_centry_info)) + gl_centry_info_size;
1486 	wsp->walk_data = winfo;
1487 
1488 	return (WALK_NEXT);
1489 }
1490 
1491 static int
1492 sdbc_glcinfo_wstep(mdb_walk_state_t *wsp)
1493 {
1494 	struct walk_info *winfo = wsp->walk_data;
1495 	int status;
1496 
1497 	if (wsp->walk_addr == NULL)
1498 		return (WALK_DONE);
1499 
1500 	if (wsp->walk_addr >= winfo->w_end)
1501 		return (WALK_DONE);
1502 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
1503 						wsp->walk_cbdata);
1504 
1505 	wsp->walk_addr += sizeof (ss_centry_info_t);
1506 
1507 	return (status);
1508 }
1509 
1510 static void
1511 sdbc_glcinfo_wfini(mdb_walk_state_t *wsp)
1512 {
1513 	mdb_free(wsp->walk_data, sizeof (struct walk_info));
1514 }
1515 
1516 /*
1517  * walk the global file info array
1518  */
1519 static int
1520 sdbc_glfinfo_winit(mdb_walk_state_t *wsp)
1521 {
1522 	ss_voldata_t *gl_file_info;
1523 	struct walk_info *winfo;
1524 	int maxdevs;
1525 
1526 
1527 	winfo = mdb_zalloc(sizeof (struct walk_info), UM_SLEEP);
1528 
1529 	/* get start of the cache entry metadata */
1530 	if (mdb_readvar(&gl_file_info, "_sdbc_gl_file_info") == -1) {
1531 		mdb_warn("failed to read  _sdbc_gl_file_info");
1532 		return (WALK_ERR);
1533 	}
1534 
1535 
1536 	if (wsp->walk_addr == NULL)
1537 		wsp->walk_addr = (uintptr_t)(gl_file_info);
1538 
1539 	/* get the number of volumes */
1540 	if (mdb_readvar(&maxdevs, "sdbc_max_devs") == -1) {
1541 		mdb_warn("failed to read  sdbc_max_devs");
1542 		return (WALK_ERR);
1543 	}
1544 
1545 	/* end of the array */
1546 	winfo->w_end = (uintptr_t)((gl_file_info) + maxdevs);
1547 
1548 	wsp->walk_data = winfo;
1549 
1550 	return (WALK_NEXT);
1551 }
1552 
1553 static int
1554 sdbc_glfinfo_wstep(mdb_walk_state_t *wsp)
1555 {
1556 	struct walk_info *winfo = wsp->walk_data;
1557 	int status;
1558 
1559 	if (wsp->walk_addr == NULL)
1560 		return (WALK_DONE);
1561 
1562 	if (wsp->walk_addr >= winfo->w_end)
1563 		return (WALK_DONE);
1564 
1565 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
1566 						wsp->walk_cbdata);
1567 
1568 	wsp->walk_addr += sizeof (ss_voldata_t);
1569 
1570 	return (status);
1571 
1572 }
1573 
1574 static void
1575 sdbc_glfinfo_wfini(mdb_walk_state_t *wsp)
1576 {
1577 	mdb_free(wsp->walk_data, sizeof (struct walk_info));
1578 }
1579 
1580 /* end of WALKERS section */
1581 
1582 
1583 const mdb_bitmask_t cc_flag_bits[] = {
1584 	{"PEND_DIRTY", CC_PEND_DIRTY, CC_PEND_DIRTY},
1585 	{"PINNED", CC_PINNED, CC_PINNED},
1586 	{"PINNABLE", CC_PINNABLE, CC_PINNABLE},
1587 	{"QHEAD", CC_QHEAD, CC_QHEAD},
1588 	{NULL, 0, 0}
1589 };
1590 
1591 const mdb_bitmask_t io_status_bits[] = {
1592 	{"IO_NONE", 0xff, _SD_IO_NONE},
1593 	{"IO_INITIATE", 0xff, _SD_IO_INITIATE},
1594 	{"IO_DONE", 0xff, _SD_IO_DONE},
1595 	{"IO_FAILED", 0xff, _SD_IO_FAILED},
1596 	{"IO_DISCARDED", 0xff, _SD_IO_DISCARDED},
1597 	{NULL, 0, 0}
1598 };
1599 
1600 const mdb_bitmask_t cc_aging_bits[] = {
1601 	{"FOUND_IN_HASH", FOUND_IN_HASH_DM, FOUND_IN_HASH_DM},
1602 	{"FOUND_HOLD_OVER", FOUND_HOLD_OVER_DM, FOUND_HOLD_OVER_DM},
1603 	{"HOST_ENTRY", HOST_ENTRY_DM, HOST_ENTRY_DM},
1604 	{"PARASITIC_ENTRY", PARASITIC_ENTRY_DM, PARASITIC_ENTRY_DM},
1605 	{"STICKY_METADATA", STICKY_METADATA_DM, STICKY_METADATA_DM},
1606 	{"ELIGIBLE_ENTRY", ELIGIBLE_ENTRY_DM, ELIGIBLE_ENTRY_DM},
1607 	{"HASH_ENTRY", HASH_ENTRY_DM, HASH_ENTRY_DM},
1608 	{"HOLD_ENTRY", HOLD_ENTRY_DM, HOLD_ENTRY_DM},
1609 	{"AVAIL_ENTRY", AVAIL_ENTRY_DM, AVAIL_ENTRY_DM},
1610 	{"BAD_CHAIN", BAD_CHAIN_DM, BAD_CHAIN_DM},
1611 	{"BAD_ENTRY", BAD_ENTRY_DM, BAD_ENTRY_DM},
1612 	{"PREFETCH_I", PREFETCH_BUF_I, PREFETCH_BUF_I},
1613 	{"PREFETCH_E", PREFETCH_BUF_E, PREFETCH_BUF_E},
1614 	{NULL, 0, 0}
1615 };
1616 
1617 
1618 /* DCMDS that use walkers */
1619 
1620 /*
1621  * dcmd to display cache entry control structures
1622  */
1623 static int
1624 sdbc_cctl(uintptr_t addr, uint_t flags, int argc,
1625 					const mdb_arg_t *argv)
1626 {
1627 	uint_t opt_a = FALSE;
1628 	uintptr_t opt_c = MDB_CD;    /* cd */
1629 	uintptr_t opt_b = MDB_BLKNUM;    /* block num */
1630 	uint_t opt_B = FALSE;    /* BAD CHAIN or ENTRY */
1631 	uint_t opt_d = FALSE;    /* dirty */
1632 	uint_t opt_H = FALSE;    /* HOST */
1633 	uint_t opt_h = FALSE;    /* hashed */
1634 	uint_t opt_i = FALSE;    /* inuse */
1635 	uint_t opt_p = FALSE;    /* pageio */
1636 	uint_t opt_P = FALSE;    /* PARASITE */
1637 	uint_t opt_R = FALSE;    /* explicit read-ahead (prefetch) */
1638 	uint_t opt_r = FALSE;    /* implicit read-ahead (prefetch) */
1639 	uint_t opt_o = FALSE;    /* io in progress */
1640 	uint_t opt_m = FALSE;	 /* has memory allocated */
1641 	uint_t opt_V = FALSE;    /* valid bits */
1642 	uint_t opt_v = FALSE;    /* verbose */
1643 	uint_t nofilter = FALSE; /* true if b, d, h, i, o, p, V are all false */
1644 	_sd_cctl_t centry;
1645 	_sd_cctl_sync_t cc_sync;
1646 
1647 	/*
1648 	 * possible enhancements -- option to filter on flag bits
1649 	 * option that toggles other options.
1650 	 */
1651 	if (mdb_getopts(argc, argv,
1652 			'a', MDB_OPT_SETBITS, TRUE, &opt_a,
1653 			'B', MDB_OPT_SETBITS, TRUE, &opt_B,
1654 			'b', MDB_OPT_UINTPTR, &opt_b,
1655 			'c', MDB_OPT_UINTPTR, &opt_c,
1656 			'd', MDB_OPT_SETBITS, TRUE, &opt_d,
1657 			'H', MDB_OPT_SETBITS, TRUE, &opt_H,
1658 			'h', MDB_OPT_SETBITS, TRUE, &opt_h,
1659 			'i', MDB_OPT_SETBITS, TRUE, &opt_i,
1660 			'o', MDB_OPT_SETBITS, TRUE, &opt_o,
1661 			'm', MDB_OPT_SETBITS, TRUE, &opt_m,
1662 			'P', MDB_OPT_SETBITS, TRUE, &opt_P,
1663 			'p', MDB_OPT_SETBITS, TRUE, &opt_p,
1664 			'R', MDB_OPT_SETBITS, TRUE, &opt_R,
1665 			'r', MDB_OPT_SETBITS, TRUE, &opt_r,
1666 			'V', MDB_OPT_SETBITS, TRUE, &opt_V,
1667 			'v', MDB_OPT_SETBITS, TRUE, &opt_v) != argc)
1668 		return (DCMD_USAGE);
1669 
1670 
1671 	nofilter = (!OPT_B_SELECTED && !opt_d && !opt_h && !opt_i &&
1672 			!opt_o && !opt_m && !opt_p && !opt_V && !opt_B &&
1673 			!opt_P && !opt_H && !opt_R && !opt_r); /* no options */
1674 
1675 	if (!(flags & DCMD_ADDRSPEC)) {
1676 		if (mdb_walk_dcmd("sdbc`sdbc_cctl", "sdbc`sdbc_cctl",
1677 					argc, argv) == -1) {
1678 			mdb_warn("failed to walk 'cctl' list");
1679 			return (DCMD_ERR);
1680 		}
1681 		return (DCMD_OK);
1682 	}
1683 
1684 	if (DCMD_HDRSPEC(flags)) {
1685 		mdb_printf("sdbc cache ctl structures:\n");
1686 	}
1687 
1688 
1689 	if (mdb_vread(&centry, sizeof (_sd_cctl_t), addr) == -1) {
1690 		mdb_warn("dcmd failed to read centry at %p", addr);
1691 		return (DCMD_ERR);
1692 	}
1693 
1694 	/* filter exclusively on a cd number if specified */
1695 	if (OPT_C_SELECTED && (centry.cc_head.hh_cd != opt_c))
1696 		return (DCMD_OK);
1697 
1698 	/* all other filters are inclusive */
1699 	if ((nofilter) ||
1700 		(OPT_B_SELECTED && (centry.cc_head.hh_blk_num == opt_b)) ||
1701 		(opt_B && (centry.cc_aging_dm &
1702 			(BAD_ENTRY_DM | BAD_CHAIN_DM))) ||
1703 		(opt_d && (centry.cc_dirty)) ||
1704 		(opt_H && (centry.cc_aging_dm & HOST_ENTRY_DM)) ||
1705 		(opt_h && (centry.cc_head.hh_hashed)) ||
1706 		(opt_i && (centry.cc_inuse)) ||
1707 		(opt_p && (centry.cc_pageio)) ||
1708 		(opt_P && (centry.cc_aging_dm & PARASITIC_ENTRY_DM)) ||
1709 		(opt_R && (centry.cc_aging_dm & PREFETCH_BUF_E)) ||
1710 		(opt_r && (centry.cc_aging_dm & PREFETCH_BUF_I)) ||
1711 		(opt_V && (centry.cc_valid)) ||
1712 		(opt_m && (centry.cc_alloc_size_dm)) ||
1713 		(opt_o && (centry.cc_iostatus != _SD_IO_NONE)))
1714 		/*EMPTY*/;
1715 	else
1716 		return (DCMD_OK);
1717 
1718 	mdb_inc_indent(4);
1719 	mdb_printf(
1720 	"%-?p cd %3-d blk_num %10-d valid %04hx dirty %04hx flag %02x\n",
1721 			addr, centry.cc_head.hh_cd,
1722 			centry.cc_head.hh_blk_num, centry.cc_valid,
1723 			centry.cc_dirty, centry.cc_flag);
1724 	mdb_dec_indent(4);
1725 
1726 	if (!opt_v)
1727 		return (DCMD_OK);
1728 
1729 	/* verbose */
1730 	mdb_inc_indent(4);
1731 	mdb_printf(
1732 	"hashed %d seq %4-d toflush %04hx %8Tawait_use %4-d await_page %4-d\n",
1733 		centry.cc_head.hh_hashed, centry.cc_seq,
1734 		centry.cc_toflush, centry.cc_await_use,
1735 		centry.cc_await_page);
1736 
1737 	mdb_printf("inuse %d pageio %d cc_flag <%b>\n",
1738 		centry.cc_inuse, centry.cc_pageio,
1739 		centry.cc_flag, cc_flag_bits);
1740 
1741 	mdb_printf("iocount %2d iostatus <%b>\n",
1742 		    centry.cc_iocount, centry.cc_iostatus, io_status_bits);
1743 
1744 	if (mdb_vread(&cc_sync, sizeof (struct _sd_cctl_sync),
1745 					(uintptr_t)centry.cc_sync)
1746 		== -1)
1747 		mdb_warn("failed to read cc_sync"); /* not catastophic */
1748 
1749 	else
1750 		mdb_printf("cc_sync blkcv: %h-x %8Tlock: 0x%p (owner)\n",
1751 				cc_sync._cc_blkcv._opaque,
1752 				cc_sync._cc_lock._opaque[0]);
1753 
1754 	mdb_printf("dynamic memory allocation:\n");
1755 	mdb_inc_indent(4);
1756 	mdb_printf("aging_dm age %3d %4Tage flags: <%b> 0x%x\n",
1757 			centry.cc_aging_dm & 0xff,
1758 			centry.cc_aging_dm, cc_aging_bits, centry.cc_aging_dm);
1759 
1760 	mdb_printf("alloc_size_dm %10-d head_dm %?-p\n",
1761 		centry.cc_alloc_size_dm, centry.cc_head_dm);
1762 	mdb_printf("next_dm %?-p link_list_dm %?-p\n",
1763 		centry.cc_next_dm, centry.cc_link_list_dm);
1764 
1765 	mdb_printf("alloc_ct_dm %10-d dealloc_ct_dm %10-d\n",
1766 		centry.cc_alloc_ct_dm, centry.cc_dealloc_ct_dm);
1767 
1768 	mdb_dec_indent(4);
1769 	/* pointers */
1770 	mdb_printf("cctl pointers:\n");
1771 	mdb_inc_indent(4);
1772 
1773 	mdb_printf("next %?-p prev %?-p chain %?-p\n",
1774 		centry.cc_next, centry.cc_prev, centry.cc_chain);
1775 	mdb_printf("dirty_next %?-p dirty_link %?-p\n",
1776 		centry.cc_dirty_next, centry.cc_dirty_link);
1777 	mdb_printf("data %?-p write ctl %?-p\n",
1778 		centry.cc_data, centry.cc_write);
1779 
1780 	mdb_dec_indent(4);
1781 
1782 	/* dynmem chain */
1783 	mdb_printf("cctl dmqueue index cc_blocks %4-d\n", centry.cc_cblocks);
1784 
1785 	mdb_printf("anon_addr %?-p anon_len %8-d\n",
1786 			centry.cc_anon_addr.sa_virt, centry.cc_anon_len);
1787 
1788 	/* stats */
1789 	mdb_printf("cctl stats:	");
1790 	mdb_inc_indent(4);
1791 	mdb_printf("hits %8-d creat time %?-p\n", centry.cc_hits,
1792 			centry.cc_creat);
1793 	mdb_dec_indent(4);
1794 
1795 	mdb_printf("\n");
1796 
1797 	mdb_dec_indent(4);
1798 
1799 	return (DCMD_OK);
1800 }
1801 
1802 
1803 /*
1804  * convenience dcmd to display the _sd_cctl cc_chain list (alloc list)
1805  * Must be called with an address of a cache entry (_sd_cctl_t)
1806  * same options as sdbc_cctl().
1807  * alternatively the user can call the sdbc_cchain walker
1808  * and pipe the addresses to sdbc_cctl dcmd.
1809  */
1810 static int
1811 sdbc_cchain(uintptr_t addr, uint_t flags, int argc,
1812 					const mdb_arg_t *argv)
1813 {
1814 
1815 	if (!(flags & DCMD_ADDRSPEC))
1816 		return (DCMD_USAGE);
1817 
1818 	if (mdb_pwalk_dcmd("sdbc`sdbc_cchain", "sdbc`sdbc_cctl",
1819 						argc, argv, addr)
1820 			== -1) {
1821 		mdb_warn("failed to walk cc_chain at addr %p", addr);
1822 		return (DCMD_ERR);
1823 	}
1824 
1825 	return (DCMD_OK);
1826 }
1827 
1828 
1829 /*
1830  * convenience dcmd to cdisplay the _sd_cctl dirty chain
1831  * (which is really a 2d chain).
1832  * Must be called with an address of a cache entry (_sd_cctl_t)
1833  * same options as sdbc_cctl().
1834  * alternatively the user can call the sdbc_dchain walker
1835  * and pipe the addresses to sdbc_cctl dcmd.
1836  */
1837 static int
1838 sdbc_dchain(uintptr_t addr, uint_t flags, int argc,
1839 					const mdb_arg_t *argv)
1840 {
1841 
1842 	if (!(flags & DCMD_ADDRSPEC))
1843 		return (DCMD_USAGE);
1844 
1845 	if (mdb_pwalk_dcmd("sdbc`sdbc_dchain", "sdbc`sdbc_cctl",
1846 						argc, argv, addr)
1847 			== -1) {
1848 		mdb_warn("failed to walk dirty chain at addr %p", addr);
1849 		return (DCMD_ERR);
1850 	}
1851 
1852 	return (DCMD_OK);
1853 }
1854 
1855 /*
1856  * convenience dcmd to display the _sd_cctl dm chain list
1857  * Must be called with an address of a cache entry (_sd_cctl_t)
1858  * same options as sdbc_cctl().
1859  * alternatively the user can call the sdbc_dmchain walker
1860  * and pipe the addresses to sdbc_cctl dcmd.
1861  */
1862 static int
1863 sdbc_dmchain(uintptr_t addr, uint_t flags, int argc,
1864 					const mdb_arg_t *argv)
1865 {
1866 
1867 	if (!(flags & DCMD_ADDRSPEC))
1868 		return (DCMD_USAGE);
1869 
1870 	if (mdb_pwalk_dcmd("sdbc`sdbc_dmchain", "sdbc`sdbc_cctl",
1871 						argc, argv, addr)
1872 			== -1) {
1873 		mdb_warn("failed to walk dm chain at addr %p", addr);
1874 		return (DCMD_ERR);
1875 	}
1876 
1877 	return (DCMD_OK);
1878 }
1879 
1880 /*
1881  * dcmd to walk a hash chain
1882  * requires an address. same options as sdbc_cctl dcmd
1883  */
1884 static int
1885 sdbc_hashchain(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1886 {
1887 	if (!(flags & DCMD_ADDRSPEC))
1888 		return (DCMD_USAGE);
1889 
1890 	if (mdb_pwalk_dcmd("sdbc`sdbc_hashchain", "sdbc`sdbc_cctl",
1891 					argc, argv, addr) == -1) {
1892 		mdb_warn("failed to walk hashchain at %p", addr);
1893 		return (DCMD_ERR);
1894 	}
1895 
1896 	return (DCMD_OK);
1897 }
1898 
1899 
1900 static void
1901 display_hash_table(_sd_hash_table_t *addr, _sd_hash_table_t *ht)
1902 {
1903 	mdb_printf("hash table (%p):\n", addr);
1904 	mdb_inc_indent(4);
1905 	mdb_printf("size %7-d bits %2-d mask %8-x nmask %8-x buckets %p\n",
1906 		ht->ht_size, ht->ht_bits, ht->ht_mask,
1907 		ht->ht_nmask, ht->ht_buckets);
1908 	mdb_dec_indent(4);
1909 }
1910 
1911 static void
1912 display_hash_bucket(_sd_hash_bucket_t *addr, _sd_hash_bucket_t *hb)
1913 {
1914 	kmutex_t lock;
1915 	int rc;
1916 
1917 	if ((rc = mdb_vread(&lock, sizeof (kmutex_t),
1918 				(uintptr_t)hb->hb_lock)) == -1)
1919 		mdb_warn("failed to read bucket lock at %p", hb->hb_lock);
1920 
1921 	mdb_printf("hash bucket (%p):\n", addr);
1922 	mdb_inc_indent(4);
1923 	mdb_printf("head %?-p tail %?-p lock %?-p %s\n",
1924 		hb->hb_head, hb->hb_tail,
1925 		(rc == -1) ? hb->hb_lock : lock._opaque[0],
1926 		(rc == -1) ? "" : "(owner)");
1927 	mdb_printf("inlist %d seq %d\n", hb->hb_inlist, hb->hb_seq);
1928 	mdb_dec_indent(4);
1929 }
1930 
1931 /*
1932  * dcmd to walk the hash table
1933  * defaults to _sd_htable the cache hash table,
1934  * but wil accept an address which is probably only useful
1935  * in the event that other hash tables are implemented in
1936  * the cache.
1937  *
1938  * calls sdbc_hashchain dcmd.  same options as sdbc_cctl dcmd.
1939  */
1940 static int
1941 sdbc_hashtable(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1942 {
1943 	_sd_hash_table_t *sd_htable_addr;
1944 	_sd_hash_table_t _sd_htable;
1945 	_sd_hash_bucket_t hash_bucket;
1946 	int i;
1947 
1948 
1949 
1950 	if (!(flags & DCMD_ADDRSPEC)) {
1951 		/* get the address of the standard cache hash table */
1952 		if (mdb_readvar(&sd_htable_addr, "_sd_htable") == -1) {
1953 			mdb_warn("failed to read _sd_htable address\n");
1954 			return (DCMD_ERR);
1955 		}
1956 	} else
1957 		sd_htable_addr = (_sd_hash_table_t *)addr;
1958 
1959 	/* read in the hash table structure */
1960 	if (mdb_vread(&_sd_htable, sizeof (_sd_hash_table_t),
1961 		(uintptr_t)sd_htable_addr) == -1) {
1962 		mdb_warn("failed to read _sd_htable structure at %p\n",
1963 						    sd_htable_addr);
1964 		return (DCMD_ERR);
1965 	}
1966 
1967 	display_hash_table(sd_htable_addr, &_sd_htable);
1968 
1969 	/*
1970 	 * read in the hash buckets
1971 	 * and display chains if there are any
1972 	 */
1973 	for (i = 0; i < _sd_htable.ht_size; ++i) {
1974 		if (mdb_vread(&hash_bucket, sizeof (_sd_hash_bucket_t),
1975 			    (uintptr_t)(_sd_htable.ht_buckets + i)) == -1) {
1976 			mdb_warn("failed to read ht_buckets at %p\n",
1977 					    _sd_htable.ht_buckets + i);
1978 			return (DCMD_ERR);
1979 		}
1980 
1981 		if (hash_bucket.hb_head != NULL) {
1982 			display_hash_bucket(_sd_htable.ht_buckets + i,
1983 							&hash_bucket);
1984 			/*
1985 			 * if this walk fails, continue trying
1986 			 * to read hash buckets
1987 			 */
1988 			if (mdb_call_dcmd("sdbc`sdbc_hashchain",
1989 					(uintptr_t)hash_bucket.hb_head,
1990 					flags|DCMD_ADDRSPEC, argc, argv)
1991 								    == -1)
1992 				    mdb_warn(
1993 					    "failed to walk hash chain at %p",
1994 					hash_bucket.hb_head);
1995 			    mdb_printf("\n");
1996 		    }
1997 	}
1998 
1999 	return (DCMD_OK);
2000 }
2001 /*
2002  * dcmd to display the sdbc lru queue
2003  * same options as sdbc_cctl().
2004  * alternatively the user can call the sdbc_lru walker
2005  * and pipe the addresses to sdbc_cctl dcmd.
2006  */
2007 static int
2008 sdbc_lru(uintptr_t addr, uint_t flags, int argc,
2009 					const mdb_arg_t *argv)
2010 {
2011 	_sd_queue_t _sd_lru_q;
2012 	GElf_Sym sym;
2013 
2014 	if (!(flags & DCMD_ADDRSPEC)) {
2015 		if (mdb_lookup_by_obj("sdbc", "_sd_lru_q", &sym) == -1) {
2016 			mdb_warn("failed to lookup _sd_lru_q symbol");
2017 			return (DCMD_ERR);
2018 		}
2019 
2020 		if (mdb_vread(&_sd_lru_q, sizeof (_sd_queue_t),
2021 						sym.st_value) == -1) {
2022 			mdb_warn("failed to read _sd_lru_q structure");
2023 			return (DCMD_ERR);
2024 		}
2025 
2026 		mdb_printf("Cache LRU Queue\n");
2027 		mdb_inc_indent(4);
2028 		mdb_printf(
2029 		"qlock: 0x%-p (owner) await %d seq %d inq %d req %d noreq %d\n",
2030 			_sd_lru_q.sq_qlock._opaque[0],
2031 			_sd_lru_q.sq_await,
2032 			_sd_lru_q.sq_seq,
2033 			_sd_lru_q.sq_inq,
2034 			_sd_lru_q.sq_req_stat,
2035 			_sd_lru_q.sq_noreq_stat);
2036 
2037 		addr = (uintptr_t)(sym.st_value);
2038 	}
2039 
2040 	if (mdb_pwalk_dcmd("sdbc`sdbc_lru", "sdbc`sdbc_cctl",
2041 					argc, argv, addr) == -1) {
2042 		mdb_warn("failed to walk lru at addr %p", addr);
2043 		return (DCMD_ERR);
2044 	}
2045 
2046 	return (DCMD_OK);
2047 }
2048 
2049 #ifdef SAFESTORE
2050 static void
2051 print_wrq(_sd_writeq_t *wrq, uint_t verbose)
2052 {
2053 	int i;
2054 
2055 	mdb_printf("Cache Write Ctl Queue:\n");
2056 	mdb_inc_indent(4);
2057 	mdb_printf("qtop %-p qlock: %-p (owner) inq %d\n",
2058 		wrq->wq_qtop,
2059 		wrq->wq_qlock._opaque[0],
2060 		wrq->wq_inq);
2061 
2062 	mdb_printf("slp_top %3-d slp_index %3-d slp_inq %3-d\n",
2063 		wrq->wq_slp_top,
2064 		wrq->wq_slp_index,
2065 		wrq->wq_slp_inq);
2066 
2067 	for (i = 0; verbose && i < SD_WR_SLP_Q_MAX; i += 2) {
2068 		mdb_printf("%3d: cv %h-x wq_need %3-d wq_held %3-d%4T",
2069 			i,
2070 			wrq->wq_slp[i].slp_wqcv._opaque,
2071 			wrq->wq_slp[i].slp_wqneed,
2072 			wrq->wq_slp[i].slp_wqheld);
2073 		if (SD_WR_SLP_Q_MAX > (i + 1)) {
2074 			mdb_printf(
2075 			"%3d: cv %h-x wq_need %3-d wq_held %3-d%\n",
2076 			    i+1,
2077 			    wrq->wq_slp[i+1].slp_wqcv._opaque,
2078 			    wrq->wq_slp[i+1].slp_wqneed,
2079 			    wrq->wq_slp[i+1].slp_wqheld);
2080 		}
2081 	}
2082 	mdb_dec_indent(4);
2083 }
2084 
2085 /*
2086  * dcmd to display write control structures
2087  */
2088 
2089 static int
2090 sdbc_wctl(uintptr_t addr, uint_t flags, int argc,
2091 					const mdb_arg_t *argv)
2092 {
2093 	_sd_wr_cctl_t wctl;
2094 	ss_centry_info_t gl_info;
2095 	ss_centry_info_t nv_gl_info;
2096 	uintptr_t opt_c = MDB_CD;
2097 	uint_t opt_d = FALSE;
2098 	uint_t opt_v = FALSE;
2099 
2100 
2101 	/* TODO option for fba pos */
2102 	if (mdb_getopts(argc, argv,
2103 			'd', MDB_OPT_SETBITS, TRUE, &opt_d,
2104 			'c', MDB_OPT_UINTPTR, &opt_c,
2105 			'v', MDB_OPT_SETBITS, TRUE, &opt_v) != argc)
2106 		return (DCMD_USAGE);
2107 
2108 
2109 	if (!(flags & DCMD_ADDRSPEC)) {
2110 		if (mdb_walk_dcmd("sdbc`sdbc_wctl", "sdbc`sdbc_wctl",
2111 					argc, argv) == -1) {
2112 			mdb_warn("failed to walk write ctl array");
2113 			return (DCMD_ERR);
2114 		}
2115 		return (DCMD_OK);
2116 	}
2117 
2118 	if (DCMD_HDRSPEC(flags)) {
2119 		mdb_printf("write control block structures:\n");
2120 	}
2121 
2122 	if (mdb_vread(&wctl, sizeof (_sd_wr_cctl_t), addr) == -1) {
2123 		mdb_warn("failed to read wctl at 0x%p", addr);
2124 		return (DCMD_ERR);
2125 	}
2126 
2127 
2128 	/*
2129 	 * print "all" is the default.
2130 	 * filter conditions can only be checked by reading in wc_gl_info
2131 	 */
2132 	if (opt_c || opt_d || opt_v)
2133 	    if (mdb_vread(&gl_info, sizeof (ss_centry_info_t),
2134 				(uintptr_t)wctl.wc_gl_info) == -1) {
2135 		    mdb_warn("failed to read at wc_gl_info 0x%p", addr);
2136 		return (DCMD_ERR);
2137 	}
2138 
2139 
2140 	if (OPT_C_SELECTED && (gl_info.gl_cd != opt_c))
2141 		return (DCMD_OK);
2142 
2143 	if (opt_d && !(gl_info.gl_dirty))
2144 		return (DCMD_OK);
2145 
2146 	mdb_inc_indent(4);
2147 	mdb_printf("%-p data %-p gl_info %-p Ngl_info %-p flg %02x\n",
2148 		addr,
2149 		wctl.wc_data,
2150 		wctl.wc_gl_info,
2151 		wctl.wc_nvmem_gl_info,
2152 		wctl.wc_flag);
2153 	mdb_dec_indent(4);
2154 
2155 	/* verbose */
2156 	if (!opt_v)
2157 		return (DCMD_OK);
2158 
2159 	mdb_inc_indent(4);
2160 	mdb_printf("next %?-p prev %?-p\n", wctl.wc_next, wctl.wc_prev);
2161 	mdb_printf("      gl_info: ");
2162 	mdb_printf("cd %3-d fpos %10-d dirty %04x flag <%b>\n",
2163 		gl_info.gl_cd, gl_info.gl_fpos, gl_info.gl_dirty & 0xffff,
2164 		gl_info.gl_flag, cc_flag_bits);
2165 
2166 	if (wctl.wc_nvmem_gl_info) {
2167 	    if (mdb_vread(&nv_gl_info, sizeof (ss_centry_info_t),
2168 				(uintptr_t)wctl.wc_nvmem_gl_info) == -1) {
2169 		    mdb_warn("failed to read at wc_nvmem_gl_info 0x%p",
2170 		    wctl.wc_nvmem_gl_info);  /* not catastophic, continue */
2171 	    } else {
2172 
2173 		    /* consistency check */
2174 			if (memcmp(&gl_info, &nv_gl_info,
2175 					sizeof (ss_centry_info_t) != 0)) {
2176 			mdb_warn("nvram and host memory are NOT identical!");
2177 			mdb_printf("nvmem_gl_info: ");
2178 			mdb_printf("cd %3-d fpos %10-d dirty %04x flag <%b>\n",
2179 			nv_gl_info.gl_cd, nv_gl_info.gl_fpos,
2180 			nv_gl_info.gl_dirty & 0xffff,
2181 			nv_gl_info.gl_flag, cc_flag_bits);
2182 		    }
2183 
2184 	    }
2185 	}
2186 
2187 	mdb_dec_indent(4);
2188 	mdb_printf("\n");
2189 	return (DCMD_OK);
2190 }
2191 
2192 /*
2193  * dcmd to display write control structures in the free list
2194  * same options as sdbc_wctl
2195  */
2196 
2197 static int
2198 sdbc_wrq(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2199 {
2200 	_sd_net_t _sd_net_config;
2201 	uintptr_t opt_c = MDB_CD;
2202 	uint_t opt_d = FALSE;
2203 	uint_t opt_v = FALSE;
2204 
2205 
2206 	/* look for verbose option */
2207 	if (mdb_getopts(argc, argv,
2208 			'd', MDB_OPT_SETBITS, TRUE, &opt_d,
2209 			'c', MDB_OPT_UINTPTR, &opt_c,
2210 			'v', MDB_OPT_SETBITS, TRUE, &opt_v) != argc)
2211 		return (DCMD_USAGE);
2212 
2213 	if (!(flags & DCMD_ADDRSPEC)) {
2214 		if (mdb_readvar(&_sd_net_config, "_sd_net_config") == -1) {
2215 			mdb_warn("failed to read _sd_net_config structure");
2216 			return (DCMD_ERR);
2217 		}
2218 
2219 		print_wrq(&(_sd_net_config.sn_wr_queue), opt_v);
2220 
2221 		addr = (uintptr_t)(_sd_net_config.sn_wr_queue.wq_qtop);
2222 	}
2223 
2224 	if (mdb_pwalk_dcmd("sdbc`sdbc_wrq", "sdbc`sdbc_wctl",
2225 					argc, argv, addr) == -1) {
2226 		mdb_warn("failed to walk write ctl queue at addr %p", addr);
2227 		return (DCMD_ERR);
2228 	}
2229 	return (DCMD_OK);
2230 }
2231 #endif
2232 
2233 /*
2234  * dcmd to display the dm queues
2235  * use sdbc_lru walker to walk each queue.
2236  */
2237 /*ARGSUSED*/
2238 static int
2239 sdbc_dmqueues(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2240 {
2241 	_sd_queue_t *sdbc_dm_queues; /* kernel address of dm queues */
2242 	int max_dm_queues;
2243 	_sd_queue_t *queues = NULL; /* local copy */
2244 	int i;
2245 
2246 
2247 	if (argc != 0)
2248 		return (DCMD_USAGE);
2249 
2250 	if (!(flags & DCMD_ADDRSPEC)) {
2251 		if (mdb_readvar(&sdbc_dm_queues, "sdbc_dm_queues") == -1) {
2252 			mdb_warn("failed to read sdbc_dm_queues address\n");
2253 			return (DCMD_ERR);
2254 		}
2255 
2256 		if (mdb_readvar(&max_dm_queues, "max_dm_queues") == -1) {
2257 			mdb_warn("failed to read max_dm_queues variable\n");
2258 			return (DCMD_ERR);
2259 		}
2260 
2261 		queues = mdb_zalloc(max_dm_queues * sizeof (_sd_queue_t),
2262 					UM_SLEEP);
2263 mdb_printf("max_dm_queues %d sdbc_dm_queues %p queues %p\n",
2264 		max_dm_queues, sdbc_dm_queues, queues);
2265 
2266 		if (mdb_vread(queues, max_dm_queues * sizeof (_sd_queue_t),
2267 					(uintptr_t)sdbc_dm_queues) == -1) {
2268 			mdb_warn("failed to read sdbc_dm_queues");
2269 			return (DCMD_ERR);
2270 		}
2271 
2272 		for (i = 0;  i < max_dm_queues; ++i) {
2273 			mdb_printf("Cache DM Queue %d %p\n",
2274 					queues[i].sq_dmchain_cblocks,
2275 					sdbc_dm_queues +i);
2276 			mdb_inc_indent(4);
2277 			mdb_printf("qlock: 0x%-p (owner) await %d "
2278 					"seq %d inq %d req %d noreq %d\n",
2279 					queues[i].sq_qlock._opaque[0],
2280 					queues[i].sq_await,
2281 					queues[i].sq_seq,
2282 					queues[i].sq_inq,
2283 					queues[i].sq_req_stat,
2284 					queues[i].sq_noreq_stat);
2285 
2286 			mdb_dec_indent(4);
2287 		}
2288 	}
2289 
2290 	return (DCMD_OK);
2291 }
2292 
2293 
2294 mdb_bitmask_t cd_writer_bits[] = {
2295 	{ "NONE   ", (u_longlong_t)~0, _SD_WRITER_NONE },
2296 	{ "CREATE ", (u_longlong_t)~0, _SD_WRITER_CREATE },
2297 	{ "RUNNING", (u_longlong_t)~0, _SD_WRITER_RUNNING },
2298 	{ NULL, 0, 0 }
2299 };
2300 
2301 mdb_bitmask_t sh_failed_status[] = {
2302 	{ "STATUS OK", (u_longlong_t)~0, 0 },
2303 	{ "I/O ERROR", (u_longlong_t)~0, 1 },
2304 	{ "OPEN FAIL", (u_longlong_t)~0, 2 },
2305 	{ NULL, 0, 0 }
2306 };
2307 
2308 mdb_bitmask_t sh_flag_bits[] = {
2309 	{ "ATTACHED", CD_ATTACHED, CD_ATTACHED },
2310 	{ NULL, 0, 0 }
2311 };
2312 
2313 mdb_bitmask_t sh_alloc_bits[] = {
2314 	{ "ALLOC_IN_PROGRESS", CD_ALLOC_IN_PROGRESS, CD_ALLOC_IN_PROGRESS },
2315 	{ "ALLOCATED", CD_ALLOCATED, CD_ALLOCATED },
2316 	{ "CLOSE_IN_PROGRESS", CD_CLOSE_IN_PROGRESS, CD_CLOSE_IN_PROGRESS },
2317 	{ NULL, 0, 0 }
2318 };
2319 
2320 /*
2321  * dcmd to display cd information
2322  */
2323 static int
2324 sdbc_cdinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2325 {
2326 	_sd_shared_t sd_shared;
2327 	_sd_cd_info_t cdi;
2328 	ss_voldata_t gl_file;
2329 	char *fn = "nopath"; /* filename if sd_shared info cannot be read */
2330 	uchar_t sh_alloc = 0; /* assume not alloc'd if sd_shared info unavail */
2331 	uintptr_t opt_c = MDB_CD;
2332 	uint_t opt_a = FALSE;
2333 	uint_t opt_v = FALSE;
2334 	int dev_t_chars;
2335 
2336 	dev_t_chars = sizeof (dev_t) * 2;	/* # chars to display dev_t */
2337 
2338 
2339 	if (mdb_getopts(argc, argv,
2340 			'a', MDB_OPT_SETBITS, TRUE, &opt_a,
2341 			'c', MDB_OPT_UINTPTR, &opt_c,
2342 			'v', MDB_OPT_SETBITS, TRUE, &opt_v) != argc)
2343 		return (DCMD_USAGE);
2344 
2345 	if (!(flags & DCMD_ADDRSPEC)) {
2346 		if (mdb_walk_dcmd("sdbc`sdbc_cdinfo", "sdbc`sdbc_cdinfo",
2347 					argc, argv) == -1) {
2348 			mdb_warn("failed to walk cd info array");
2349 			return (DCMD_ERR);
2350 		}
2351 		return (DCMD_OK);
2352 	}
2353 
2354 	if (DCMD_HDRSPEC(flags)) {
2355 		mdb_printf("cd info structures:\n");
2356 	}
2357 
2358 	if (mdb_vread(&cdi, sizeof (_sd_cd_info_t), addr) == -1) {
2359 		mdb_warn("failed to read cd info at 0x%p", addr);
2360 		return (DCMD_ERR);
2361 	}
2362 
2363 	/*
2364 	 * need to do this read even for non-verbose option to
2365 	 * get the filename and the sh_alloc field
2366 	 */
2367 	if (cdi.cd_info) {
2368 	    if (mdb_vread(&sd_shared, sizeof (_sd_shared_t),
2369 				    (uintptr_t)cdi.cd_info) == -1) {
2370 		    mdb_warn("failed to read shared cd info at 0x%p",
2371 						    cdi.cd_info);
2372 		    /* not catastrophic, keep truckin' */
2373 	    } else {
2374 		    fn = sd_shared.sh_filename;
2375 		    sh_alloc = sd_shared.sh_alloc;
2376 	    }
2377 	}
2378 
2379 	if (!opt_a && (sh_alloc == 0))
2380 		return (DCMD_OK);
2381 
2382 	if (OPT_C_SELECTED && (opt_c != cdi.cd_desc))
2383 		return (DCMD_OK);
2384 
2385 	mdb_inc_indent(4);
2386 	mdb_printf("%p cd %3-d filename %s\n",
2387 		addr, cdi.cd_desc, fn);
2388 	mdb_printf("alloc <%b> hint <%b>\n",
2389 		sh_alloc, sh_alloc_bits,
2390 		cdi.cd_hint, cache_hints);
2391 	mdb_dec_indent(4);
2392 
2393 	if (!opt_v)
2394 		return (DCMD_OK);
2395 
2396 	/* verbose */
2397 	mdb_inc_indent(4);
2398 	mdb_printf("rawfd %?-p crdev %0*lx iodev %?-p\n",
2399 		cdi.cd_rawfd,
2400 		dev_t_chars,
2401 		cdi.cd_crdev,
2402 		cdi.cd_iodev);
2403 	mdb_printf("flag %x %8Tlock %?-p writer <%b>\n",
2404 		cdi.cd_flag,
2405 		cdi.cd_lock._opaque[0],
2406 		cdi.cd_writer, cd_writer_bits);
2407 	mdb_printf("global %?-p dirty_head %?-p\n",
2408 		cdi.cd_global, cdi.cd_dirty_head);
2409 	mdb_printf("last_ent %?-p lastchain_ptr %?-p lastchain %d\n",
2410 		cdi.cd_last_ent, cdi.cd_lastchain_ptr,
2411 		cdi.cd_lastchain);
2412 	mdb_printf("io_head %?-p io_tail %?-p fail_head %?-p\n",
2413 		cdi.cd_io_head, cdi.cd_io_tail, cdi.cd_fail_head);
2414 	mdb_printf(
2415 	    "cd_info %?-p failover %d recovering %d write_inprogress %d\n",
2416 		cdi.cd_info, cdi.cd_failover,
2417 		cdi.cd_recovering,
2418 		cdi.cd_write_inprogress);
2419 
2420 	if (cdi.cd_global != NULL) {
2421 		if (mdb_vread(&gl_file, sizeof (ss_voldata_t),
2422 					(uintptr_t)cdi.cd_global) == -1)
2423 			mdb_warn("failed to read cd_global at %p",
2424 						    cdi.cd_global);
2425 		else {
2426 			mdb_printf("cd_global: %s\n", gl_file.sv_volname);
2427 			mdb_printf("pinned %2-d attached %2-d devidsz %3-d\n",
2428 				gl_file.sv_pinned, gl_file.sv_attached,
2429 				gl_file.sv_devidsz);
2430 			mdb_printf("devid %s\n", gl_file.sv_devid);
2431 			mdb_printf("vol %?p\n", gl_file.sv_vol);
2432 		}
2433 		/* TODO do a consistency check here against the nvram copy */
2434 	}
2435 
2436 	if (cdi.cd_info == NULL) {
2437 		mdb_printf("no shared info\n");
2438 	} else {
2439 		mdb_printf("shared:\n");
2440 		mdb_printf("failed <%b> cd %3-d",
2441 		    sd_shared.sh_failed, sh_failed_status,
2442 		    sd_shared.sh_cd);
2443 		mdb_printf("cache_read %10-d cache_write %10-d\n",
2444 		    sd_shared.sh_cache_read, sd_shared.sh_cache_write);
2445 		mdb_printf("disk_read %10-d disk_write %10-d filesize %10-d\n",
2446 		    sd_shared.sh_disk_read, sd_shared.sh_disk_write,
2447 		    sd_shared.sh_filesize);
2448 		mdb_printf("numdirty %8-d numio %8-d numfail %8-d\n",
2449 		    sd_shared.sh_numdirty,
2450 		    sd_shared.sh_numio,
2451 		    sd_shared.sh_numfail);
2452 		mdb_printf("flushloop %2-d sh_flag <%b>\n",
2453 		    sd_shared.sh_flushloop, sd_shared.sh_flag, sh_flag_bits);
2454 
2455 		/* this can be really verbose */
2456 		if (cdi.cd_dirty_head) {
2457 			mdb_printf("Dirty Chain (cd_dirty_head):");
2458 			/* TODO reconstruct argv without opt_a */
2459 			if (!opt_a)
2460 				mdb_call_dcmd("sdbc_dchain",
2461 					(uintptr_t)cdi.cd_dirty_head,
2462 					flags, argc, argv);
2463 			else /* print with no options */
2464 				mdb_call_dcmd("sdbc_dchain",
2465 					(uintptr_t)cdi.cd_dirty_head,
2466 					flags, 0, NULL);
2467 		}
2468 
2469 		if (cdi.cd_io_head) {
2470 			mdb_printf("I/O Pending Chain (cd_io_head):");
2471 			/* TODO reconstruct argv without opt_a */
2472 			if (!opt_a)
2473 				mdb_call_dcmd("sdbc_dchain",
2474 					(uintptr_t)cdi.cd_io_head,
2475 					flags, argc, argv);
2476 			else /* print with no options */
2477 				mdb_call_dcmd("sdbc_dchain",
2478 					(uintptr_t)cdi.cd_dirty_head,
2479 					flags, 0, NULL);
2480 		}
2481 
2482 		if (cdi.cd_fail_head) {
2483 			mdb_printf("Failed Chain (cd_fail_head):");
2484 			/* TODO reconstruct argv without opt_a */
2485 			if (!opt_a)
2486 				mdb_call_dcmd("sdbc_dchain",
2487 					(uintptr_t)cdi.cd_fail_head,
2488 					flags, argc, argv);
2489 			else /* print with no options */
2490 				mdb_call_dcmd("sdbc_dchain",
2491 					(uintptr_t)cdi.cd_dirty_head,
2492 					flags, 0, NULL);
2493 		}
2494 	}
2495 
2496 	mdb_dec_indent(4);
2497 
2498 	mdb_printf("\n");
2499 
2500 	return (DCMD_OK);
2501 }
2502 
2503 #ifdef SAFESTORE
2504 /*
2505  * dcmd to display fault tolerant control structures
2506  */
2507 static int
2508 sdbc_ftctl(uintptr_t addr, uint_t flags, int argc,
2509 					const mdb_arg_t *argv)
2510 {
2511 	_sd_ft_cctl_t ft_cent;
2512 	ss_centry_info_t gl_info;
2513 	ss_centry_info_t nv_gl_info;
2514 	uintptr_t opt_c = MDB_CD;
2515 	uint_t opt_d = FALSE;
2516 	uint_t opt_v = FALSE;
2517 
2518 
2519 	/* TODO option to select on fpos */
2520 	if (mdb_getopts(argc, argv,
2521 			'd', MDB_OPT_SETBITS, TRUE, &opt_d,
2522 			'c', MDB_OPT_UINTPTR, &opt_c,
2523 			'v', MDB_OPT_SETBITS, TRUE, &opt_v) != argc)
2524 		return (DCMD_USAGE);
2525 
2526 
2527 	if (!(flags & DCMD_ADDRSPEC)) {
2528 		if (mdb_walk_dcmd("sdbc`sdbc_ftctl", "sdbc`sdbc_ftctl",
2529 					argc, argv) == -1) {
2530 			mdb_warn("failed to walk write ctl array");
2531 			return (DCMD_ERR);
2532 		}
2533 		return (DCMD_OK);
2534 	}
2535 
2536 	if (DCMD_HDRSPEC(flags)) {
2537 		mdb_printf("Ft control block structures:\n");
2538 	}
2539 
2540 	if (mdb_vread(&ft_cent, sizeof (_sd_ft_cctl_t), addr) == -1) {
2541 		mdb_warn("failed to read ft_cent at 0x%p", addr);
2542 		return (DCMD_ERR);
2543 	}
2544 
2545 
2546 	/*
2547 	 * print "all" is the default.
2548 	 * filter conditions can only be checked by reading in wc_gl_info
2549 	 */
2550 	if (opt_c || opt_d || opt_v)
2551 	    if (mdb_vread(&gl_info, sizeof (ss_centry_info_t),
2552 				(uintptr_t)ft_cent.ft_gl_info) == -1) {
2553 		mdb_warn("failed to read at wc_gl_info 0x%p", addr);
2554 		return (DCMD_ERR);
2555 	}
2556 
2557 
2558 	if (OPT_C_SELECTED && (gl_info.gl_cd != opt_c))
2559 		return (DCMD_OK);
2560 
2561 	if (opt_d && !(gl_info.gl_dirty))
2562 		return (DCMD_OK);
2563 
2564 	mdb_inc_indent(4);
2565 	mdb_printf("%-p data %?-p qnext %?-p\n",
2566 		addr,
2567 		ft_cent.ft_qnext,
2568 		ft_cent.ft_data);
2569 	mdb_printf("gl_info %?-p nvmem_gl_info %?-p\n",
2570 		ft_cent.ft_gl_info,
2571 		ft_cent.ft_nvmem_gl_info);
2572 	mdb_dec_indent(4);
2573 
2574 	/* verbose */
2575 	if (!opt_v) {
2576 		mdb_printf("\n");
2577 		return (DCMD_OK);
2578 	}
2579 
2580 	mdb_inc_indent(4);
2581 	mdb_printf("      gl_info: ");
2582 	mdb_printf("cd %3-d fpos %10-d dirty %04x flag <%b>\n",
2583 		gl_info.gl_cd, gl_info.gl_fpos, gl_info.gl_dirty & 0xffff,
2584 		gl_info.gl_flag, cc_flag_bits);
2585 
2586 	if (ft_cent.ft_nvmem_gl_info) {
2587 	    if (mdb_vread(&nv_gl_info, sizeof (ss_centry_info_t),
2588 				(uintptr_t)ft_cent.ft_nvmem_gl_info) == -1) {
2589 		    mdb_warn("failed to read at ft_nvmem_gl_info 0x%p",
2590 		    ft_cent.ft_nvmem_gl_info);  /* not catastophic, continue */
2591 	    } else {
2592 		    mdb_printf("nvmem_gl_info: ");
2593 		    mdb_printf("cd %3-d fpos %10-d dirty %04x flag <%b>\n",
2594 		    nv_gl_info.gl_cd, nv_gl_info.gl_fpos,
2595 		    nv_gl_info.gl_dirty & 0xffff,
2596 		    nv_gl_info.gl_flag, cc_flag_bits);
2597 
2598 		    /* consistency check */
2599 		    if (memcmp(&gl_info, &nv_gl_info, sizeof (ss_centry_info_t))
2600 								!= 0) {
2601 			mdb_warn("nvram and host memory are NOT identical!");
2602 		    }
2603 
2604 	    }
2605 	}
2606 
2607 	mdb_dec_indent(4);
2608 	mdb_printf("\n");
2609 	return (DCMD_OK);
2610 }
2611 #endif /* SAFESTORE */
2612 
2613 
2614 /* dcmd to display buffer handles */
2615 static int
2616 sdbc_handles(uintptr_t addr, uint_t flags, int argc,
2617 					const mdb_arg_t *argv)
2618 {
2619 	uint_t opt_a = FALSE;
2620 	uintptr_t opt_c = MDB_CD;
2621 	uint_t opt_v = FALSE;
2622 	uint_t opt_C = FALSE;
2623 	_sd_buf_hlist_t hl;
2624 	_sd_buf_handle_t bh;
2625 
2626 
2627 	if (mdb_getopts(argc, argv,
2628 			'a', MDB_OPT_SETBITS, TRUE, &opt_a,
2629 			'c', MDB_OPT_UINTPTR, &opt_c,
2630 			'C', MDB_OPT_SETBITS, TRUE, &opt_C,
2631 			'v', MDB_OPT_SETBITS, TRUE, &opt_v) != argc)
2632 		return (DCMD_USAGE);
2633 
2634 
2635 	if (mdb_readvar(&hl, "_sd_handle_list") == -1) {
2636 		mdb_warn("failed to read _sd_handle_list structure");
2637 		return (DCMD_ERR);
2638 	}
2639 
2640 
2641 	if (!(flags & DCMD_ADDRSPEC)) {
2642 		if (mdb_walk_dcmd("sdbc`sdbc_handles", "sdbc`sdbc_handles",
2643 					argc, argv) == -1) {
2644 			mdb_warn("failed to walk 'sdbc_handle_list'");
2645 			return (DCMD_ERR);
2646 		}
2647 		return (DCMD_OK);
2648 	}
2649 
2650 	if (DCMD_HDRSPEC(flags)) {
2651 		mdb_printf("Handle List Info:\n");
2652 
2653 		mdb_inc_indent(4);
2654 		mdb_printf("hl_top.bh_next: 0x%p\n", hl.hl_top.bh_next);
2655 		mdb_printf("hl_lock: 0x%p (owner)\n", hl.hl_lock._opaque[0]);
2656 		mdb_printf("hl_count: %hd\n", hl.hl_count);
2657 		mdb_dec_indent(4);
2658 		mdb_printf("buf handles:\n");
2659 	}
2660 
2661 	if (mdb_vread(&bh, sizeof (bh), addr) == -1) {
2662 		mdb_warn("failed to read buf handle at 0x%p", addr);
2663 		return (DCMD_ERR);
2664 	}
2665 
2666 	if (!opt_a && !(bh.bh_flag & (NSC_HALLOCATED | NSC_HACTIVE)))
2667 		return (DCMD_OK);
2668 
2669 	/*
2670 	 * may get false matches on cd option --
2671 	 * a cleared bh_cd field will match if user specified cd 0
2672 	 */
2673 	if (OPT_C_SELECTED && (bh.bh_cd != opt_c))
2674 		return (DCMD_OK);
2675 
2676 	mdb_inc_indent(4);
2677 	mdb_printf("%p %8T cd %3-d %4T<%b> %x\n", addr, bh.bh_cd,
2678 					bh.bh_flag, nsc_buf_bits, bh.bh_flag);
2679 
2680 	/* check for verbose, avoid printing twice */
2681 	if (!opt_v && opt_C) {
2682 		mdb_printf("cc_chain: ");
2683 		if (bh.bh_centry)
2684 			mdb_call_dcmd("sdbc`sdbc_cchain",
2685 			    (uintptr_t)bh.bh_centry, DCMD_ADDRSPEC, 0, NULL);
2686 	}
2687 
2688 	mdb_dec_indent(4);
2689 
2690 	if (!opt_v)
2691 		return (DCMD_OK);
2692 
2693 	/* verbose */
2694 	mdb_inc_indent(4);
2695 
2696 	mdb_printf("callbacks: %-20a%-20a%-20a\n",
2697 	    bh.bh_disconnect_cb, bh.bh_read_cb, bh.bh_write_cb);
2698 
2699 	mdb_printf("centry %?p %8T next %?p\n",
2700 				bh.bh_centry, bh.bh_next);
2701 	mdb_printf("buffer:\n");
2702 
2703 	mdb_inc_indent(4);
2704 	mdb_printf("fd 0x%p pos %10d len %6d flag 0x%x\n",
2705 		    bh.bh_buf.sb_fd, bh.bh_fba_pos, bh.bh_fba_len, bh.bh_flag);
2706 
2707 	mdb_printf("alloc_thread %p busy_thread %p\n", bh.bh_alloc_thread,
2708 			bh.bh_busy_thread);
2709 
2710 	mdb_printf("err %4d %8T bh_vec 0x%p\n", bh.bh_error, bh.bh_vec);
2711 	mdb_dec_indent(4);
2712 
2713 	mdb_printf("bufvec (scatter gather list): %-?s %8T%-s\n",
2714 						"ADDR", "LEN");
2715 	{
2716 		_sd_bufvec_t *bv, *endvec;
2717 
2718 
2719 		/* todo check for (bh_vec != bh_bufvec) => readahead? */
2720 
2721 		bv = bh.bh_bufvec;
2722 		endvec = bv + _SD_MAX_BLKS;
2723 		mdb_inc_indent(30);
2724 		while (bv->bufaddr) {
2725 			mdb_printf("%p    %8T%d\n", bv->bufaddr, bv->buflen);
2726 			++bv;
2727 			if (bv > endvec) {
2728 				mdb_warn("END of bh_bufvec ARRAY");
2729 				break;
2730 			}
2731 		}
2732 		mdb_dec_indent(30);
2733 	}
2734 
2735 	if (opt_C) {
2736 		mdb_printf("cc_chain: ");
2737 		if (bh.bh_centry)
2738 			mdb_call_dcmd("sdbc`sdbc_cchain",
2739 			    (uintptr_t)bh.bh_centry, DCMD_ADDRSPEC, 0, NULL);
2740 	}
2741 
2742 	mdb_dec_indent(4);
2743 	mdb_printf("\n");
2744 
2745 	return (DCMD_OK);
2746 }
2747 /*
2748  * dcmd to display ss_centry_info_t structures and
2749  * do optional consistency check with the nvram copy
2750  * if configured for nvram safe storage.
2751  */
2752 
2753 static int
2754 sdbc_glcinfo(uintptr_t addr, uint_t flags, int argc,
2755 					const mdb_arg_t *argv)
2756 {
2757 	ss_centry_info_t gl_centry_info;
2758 	/* for doing consistency check */
2759 
2760 	ss_centry_info_t *gl_centry_info_start;
2761 	ss_centry_info_t *nv_gl_centry_info_start;
2762 	uintptr_t nv_addr;
2763 	ss_centry_info_t nv_gl_centry_info;
2764 
2765 	/* options */
2766 	uint_t opt_a = FALSE;
2767 	uintptr_t opt_b = MDB_BLKNUM;	/* fba pos match */
2768 	uintptr_t opt_c = MDB_CD;
2769 	uintptr_t opt_C = FALSE; /* consistency check */
2770 	uint_t opt_d = FALSE;
2771 
2772 
2773 
2774 	if (mdb_getopts(argc, argv,
2775 			'a', MDB_OPT_SETBITS, TRUE, &opt_a,
2776 			'b', MDB_OPT_UINTPTR, &opt_b,
2777 			'c', MDB_OPT_UINTPTR, &opt_c,
2778 			'C', MDB_OPT_SETBITS, TRUE, &opt_C,
2779 			'd', MDB_OPT_SETBITS, TRUE, &opt_d) != argc)
2780 		return (DCMD_USAGE);
2781 
2782 
2783 	if (!(flags & DCMD_ADDRSPEC)) {
2784 		if (mdb_walk_dcmd("sdbc`sdbc_glcinfo", "sdbc`sdbc_glcinfo",
2785 					argc, argv) == -1) {
2786 			mdb_warn("failed to walk global centry info array");
2787 			return (DCMD_ERR);
2788 		}
2789 		return (DCMD_OK);
2790 	}
2791 
2792 	if (DCMD_HDRSPEC(flags)) {
2793 		mdb_printf("global cache entry info:\n");
2794 	}
2795 
2796 	if (mdb_vread(&gl_centry_info, sizeof (ss_centry_info_t), addr) == -1) {
2797 		mdb_warn("failed to read gl_centry_info at 0x%p", addr);
2798 		return (DCMD_ERR);
2799 	}
2800 
2801 
2802 	/*
2803 	 * default is to print entries initialized with a cd.  return if
2804 	 * no options are selected and cd is invalid.
2805 	 */
2806 	if (!opt_a && (!OPT_B_SELECTED) && (!OPT_C_SELECTED) && !opt_d &&
2807 		(gl_centry_info.sc_cd == -1))
2808 		return (DCMD_OK);
2809 
2810 
2811 	/*
2812 	 * opt_c is exclusive filter. if opt_c is selected and there
2813 	 * is no match on the cd then return
2814 	 */
2815 	if (!opt_a &&
2816 		(OPT_C_SELECTED && (gl_centry_info.sc_cd != opt_c)))
2817 		return (DCMD_OK);
2818 
2819 	/*
2820 	 * opt_d and opt_b are inclusive. print if either one is chosen
2821 	 * and the selection condition is true.
2822 	 */
2823 	if (opt_a ||
2824 	    (!opt_d && (!OPT_B_SELECTED)) || /* no options chosen */
2825 	    (opt_d && gl_centry_info.sc_dirty) ||
2826 	    (OPT_B_SELECTED && (gl_centry_info.sc_fpos == opt_b)))
2827 		/*EMPTY*/;
2828 	else
2829 		return (DCMD_OK);
2830 
2831 	mdb_inc_indent(4);
2832 	mdb_printf("%?-p cd %3-d fpos %10-d dirty %04x flag <%b>\n",
2833 		addr,
2834 		gl_centry_info.sc_cd,
2835 		gl_centry_info.sc_fpos,
2836 		gl_centry_info.sc_dirty & 0xffff,
2837 		gl_centry_info.sc_flag, cc_flag_bits);
2838 
2839 	if (opt_C) {
2840 		/* get start of the cache entry metadata */
2841 		if (mdb_readvar(&gl_centry_info_start,
2842 				"_sdbc_gl_centry_info") == -1) {
2843 			mdb_warn("failed to read  _sdbc_gl_centry_info");
2844 			/* not catastrophic */
2845 			goto end;
2846 		}
2847 
2848 		/* get start of the nvram copy cache entry metadata */
2849 		if (mdb_readvar(&nv_gl_centry_info_start,
2850 				"_sdbc_gl_centry_info_nvmem") == -1) {
2851 			mdb_warn("failed to read  _sdbc_gl_centry_info_nvmem");
2852 			/* not catastrophic */
2853 			goto end;
2854 		}
2855 
2856 		nv_addr = (addr - (uintptr_t)gl_centry_info_start) +
2857 				(uintptr_t)nv_gl_centry_info_start;
2858 
2859 		if (mdb_vread(&nv_gl_centry_info, sizeof (ss_centry_info_t),
2860 						    nv_addr) == -1) {
2861 			mdb_warn("failed to read at nvmem_gl_info 0x%p",
2862 					nv_addr);
2863 		    /* not catastophic, continue */
2864 	    } else {
2865 
2866 			/* consistency check */
2867 			mdb_inc_indent(4);
2868 			if (memcmp(&gl_centry_info, &nv_gl_centry_info,
2869 					sizeof (ss_centry_info_t) != 0)) {
2870 				mdb_warn(
2871 				"nvram and host memory are NOT identical!");
2872 				mdb_printf("nvmem_gl_centry_info: ");
2873 				mdb_printf(
2874 			    "%?-p cd %3-d fpos %10-d dirty %04x flag <%b>\n",
2875 				nv_addr,
2876 				nv_gl_centry_info.sc_cd,
2877 				nv_gl_centry_info.sc_fpos,
2878 				nv_gl_centry_info.sc_dirty & 0xffff,
2879 				nv_gl_centry_info.sc_flag, cc_flag_bits);
2880 				mdb_printf("\n");
2881 		    } else
2882 				mdb_printf("NVRAM ok\n");
2883 
2884 		    mdb_dec_indent(4);
2885 
2886 	    }
2887 	}
2888 
2889 	end:
2890 	mdb_dec_indent(4);
2891 	return (DCMD_OK);
2892 }
2893 
2894 /*
2895  * dcmd to display ss_voldata_t structures and
2896  * do optional consistency check with the nvram copy
2897  * if configured for nvram safe storage.
2898  */
2899 
2900 static int
2901 sdbc_glfinfo(uintptr_t addr, uint_t flags, int argc,
2902 					const mdb_arg_t *argv)
2903 {
2904 	ss_voldata_t gl_file_info;
2905 	/* for doing consistency check */
2906 
2907 	ss_voldata_t *gl_file_info_start;
2908 	ss_voldata_t *nv_gl_file_info_start;
2909 	uintptr_t nv_addr;
2910 	ss_voldata_t nv_gl_file_info;
2911 
2912 	/* options  default: valid filename */
2913 	uint_t opt_a = FALSE; /* all */
2914 	uint_t opt_p = FALSE; /* PINNED */
2915 	uint_t opt_t = FALSE; /* attached */
2916 	uint_t opt_C = FALSE; /* consistency check */
2917 
2918 
2919 
2920 	/*
2921 	 * possible enhancement -- match on filename,
2922 	 * or filename part (e.g. controller number)
2923 	 */
2924 	if (mdb_getopts(argc, argv,
2925 			'a', MDB_OPT_SETBITS, TRUE, &opt_a,
2926 			'C', MDB_OPT_SETBITS, TRUE, &opt_C,
2927 			'p', MDB_OPT_SETBITS, TRUE, &opt_p,
2928 			't', MDB_OPT_SETBITS, TRUE, &opt_t) != argc)
2929 		return (DCMD_USAGE);
2930 
2931 
2932 	if (!(flags & DCMD_ADDRSPEC)) {
2933 		if (mdb_walk_dcmd("sdbc`sdbc_glfinfo", "sdbc`sdbc_glfinfo",
2934 					argc, argv) == -1) {
2935 			mdb_warn("failed to walk global file info array");
2936 			return (DCMD_ERR);
2937 		}
2938 		return (DCMD_OK);
2939 	}
2940 
2941 	if (DCMD_HDRSPEC(flags)) {
2942 		mdb_printf("global file entry info:\n");
2943 	}
2944 
2945 	if (mdb_vread(&gl_file_info, sizeof (ss_voldata_t), addr) == -1) {
2946 		mdb_warn("failed to read gl_file_info at 0x%p", addr);
2947 		return (DCMD_ERR);
2948 	}
2949 
2950 
2951 	/*
2952 	 * default is to print entries initialized with non-null filename.
2953 	 * return if no options are selected and filename is invalid.
2954 	 */
2955 	if (!opt_a && !opt_p && !opt_t &&
2956 		(strlen(gl_file_info.sv_volname) == 0))
2957 		return (DCMD_OK);
2958 
2959 
2960 	if (opt_a ||
2961 		(!opt_p && !opt_t) || /* no options chosen */
2962 		(opt_p && (gl_file_info.sv_pinned != _SD_NO_HOST)) ||
2963 		(opt_t && (gl_file_info.sv_attached != _SD_NO_HOST)))
2964 		/*EMPTY*/;
2965 	else
2966 		return (DCMD_OK);
2967 
2968 	mdb_inc_indent(4);
2969 	mdb_printf("%?-p %s\n", addr, gl_file_info.sv_volname);
2970 	mdb_printf("pinned %2-d attached %2-d devidsz %3-d\n",
2971 		gl_file_info.sv_pinned,
2972 		gl_file_info.sv_attached,
2973 		gl_file_info.sv_devidsz);
2974 	mdb_printf("devid %s\n", gl_file_info.sv_devid);
2975 
2976 	if (opt_C) {
2977 		/* get start of the cache entry metadata */
2978 		if (mdb_readvar(&gl_file_info_start,
2979 				"_sdbc_gl_file_info") == -1) {
2980 			mdb_warn("failed to read  _sdbc_gl_file_info");
2981 			/* not catastrophic */
2982 			goto end;
2983 		}
2984 
2985 		/* get start of the nvram copy cache entry metadata */
2986 		if (mdb_readvar(&nv_gl_file_info_start,
2987 				"_sdbc_gl_file_info_nvmem") == -1) {
2988 			mdb_warn("failed to read  _sdbc_gl_file_info_nvmem");
2989 			/* not catastrophic */
2990 			goto end;
2991 		}
2992 
2993 		nv_addr = (addr - (uintptr_t)gl_file_info_start) +
2994 				(uintptr_t)nv_gl_file_info_start;
2995 
2996 		if (mdb_vread(&nv_gl_file_info, sizeof (ss_voldata_t),
2997 						    nv_addr) == -1) {
2998 			mdb_warn("failed to read nvmem_gl_info at 0x%p",
2999 					nv_addr);
3000 		    /* not catastophic, continue */
3001 	    } else {
3002 
3003 		    /* consistency check */
3004 		    mdb_inc_indent(4);
3005 		    if (memcmp(&gl_file_info, &nv_gl_file_info,
3006 				sizeof (ss_centry_info_t) != 0)) {
3007 			mdb_warn("nvram and host memory are NOT identical!");
3008 			mdb_printf("nvmem_gl_file_info: ");
3009 			mdb_printf("%?-p %s\n", nv_addr,
3010 					nv_gl_file_info.sv_volname);
3011 			mdb_printf("pinned %2-d attached %2-d devidsz %3-d\n",
3012 				nv_gl_file_info.sv_pinned,
3013 				nv_gl_file_info.sv_attached,
3014 				nv_gl_file_info.sv_devidsz);
3015 			mdb_printf("devid %s\n", nv_gl_file_info.sv_devid);
3016 		    } else
3017 			mdb_printf("NVRAM ok\n");
3018 
3019 		    mdb_dec_indent(4);
3020 
3021 	    }
3022 	}
3023 
3024 	end:
3025 	mdb_dec_indent(4);
3026 	mdb_printf("\n");
3027 	return (DCMD_OK);
3028 }
3029 
3030 
3031 /*
3032  * MDB module linkage information:
3033  *
3034  * We declare a list of structures describing our dcmds, and a function
3035  * named _mdb_init to return a pointer to our module information.
3036  */
3037 
3038 static const mdb_dcmd_t dcmds[] = {
3039 	/* general dcmds */
3040 	{ "sdbc_config", NULL,
3041 		"display sdbc configuration information",
3042 		sdbc_config },
3043 	{ "sdbc_stats", NULL,
3044 		"display sdbc stats information",
3045 		sdbc_stats },
3046 	{ "sdbc_vars", NULL,
3047 		"display some sdbc variables, counters and addresses",
3048 		sdbc_vars },
3049 
3050 	/* cctl dcmds */
3051 	{"sdbc_cctl", "?[-vdhioV][-c cd][-b blknum]",
3052 		"display sdbc cache ctl structures",
3053 		sdbc_cctl, cctl_help },
3054 	{"sdbc_cchain", ":[-vdhioV][-c cd][-b blknum]",
3055 		"display cache ctl structure cc_chain",
3056 		sdbc_cchain, cchain_help },
3057 	{"sdbc_dchain", ":[-vdhioV][-c cd][-b blknum]",
3058 		"display cache ctl structure dirty chain",
3059 		sdbc_dchain, dchain_help },
3060 	{"sdbc_dmchain", ":[-vdhioV][-c cd][-b blknum]",
3061 		"display dynamic memory cache ctl chain",
3062 		sdbc_dmchain, dmchain_help },
3063 	{"sdbc_hashchain", ":[-vdhioV][-c cd][-b blknum]",
3064 		"display a hash chain", sdbc_hashchain, hashchain_help },
3065 	{"sdbc_hashtable", "?[-vdhioV][-c cd][-b blknum]",
3066 		"display hash table", sdbc_hashtable, hashtable_help },
3067 	{"sdbc_lru", "?[-vdhioV][-c cd][-b blknum]",
3068 		"display the cache lru queue",
3069 		sdbc_lru, lru_help },
3070 #ifdef SAFESTORE
3071 	/* wctl dcmds */
3072 	{"sdbc_wctl", "?[-vd][-c cd]",
3073 		"display the write control structures",
3074 		sdbc_wctl, wctl_help },
3075 	{"sdbc_wrq", "?[-vd][-c cd]",
3076 		"display the write control queue",
3077 		sdbc_wrq, wrq_help },
3078 #endif /* SAFESTORE */
3079 
3080 	/* others */
3081 	{"sdbc_cdinfo", "?[-av][-c cd]",
3082 		"display cache descriptor information",
3083 		sdbc_cdinfo, cdinfo_help },
3084 #ifdef SAFESTORE
3085 	{"sdbc_ftctl", "?[-vd][-c cd]",
3086 		"display the fault tolerant control structures",
3087 		sdbc_ftctl, ftctl_help },
3088 #endif /* SAFESTORE */
3089 	{"sdbc_handles", "?[-avC][-c cd]",
3090 		"display sdbc buffer handle information",
3091 		sdbc_handles, handle_help },
3092 
3093 	{ "sdbc_dmqueues", NULL,
3094 		"display sdbc dynamic memory buffer queues information",
3095 		sdbc_dmqueues },
3096 
3097 	/* "global" metadata dcmds */
3098 	{"sdbc_glcinfo", "?[-adC][-c cd][-b fbapos]",
3099 		"display the global cache entry info structures",
3100 		sdbc_glcinfo, glcinfo_help },
3101 	{"sdbc_glfinfo", "?[-aptC]",
3102 		"display the global file info structures",
3103 		sdbc_glfinfo, glfinfo_help },
3104 	{ NULL }
3105 };
3106 
3107 static const mdb_walker_t walkers[] = {
3108 	/* walkers of cctl list and arrays */
3109 	{ "sdbc_cchain", "walk the cc_chain (alloc chain) of a cache ctl",
3110 		sdbc_cchain_winit, sdbc_cchain_wstep, sdbc_cchain_wfini },
3111 	{ "sdbc_cctl", "walk the cache ctl structure list",
3112 		sdbc_cctl_winit, sdbc_cctl_wstep, sdbc_cctl_wfini },
3113 	{ "sdbc_dchain", "walk the dirty chain of a cache ctl",
3114 		sdbc_dchain_winit, sdbc_dchain_wstep, sdbc_dchain_wfini },
3115 	{ "sdbc_dmchain", "walk the dynamic memory chain of a cache cctl",
3116 		sdbc_dmchain_winit, sdbc_dmchain_wstep, sdbc_dmchain_wfini },
3117 	{ "sdbc_hashchain", "walk a hash chain",
3118 		sdbc_hashchain_winit, sdbc_hashchain_wstep,
3119 					sdbc_hashchain_wfini },
3120 	{ "sdbc_lru", "walk the cache lru queue",
3121 		sdbc_lru_winit, sdbc_lru_wstep, sdbc_lru_wfini },
3122 
3123 #ifdef SAFESTORE
3124 	/* walkers of wctl lists and arrays */
3125 	{ "sdbc_wctl", "walk the allocated write ctl array",
3126 		sdbc_wctl_winit, sdbc_wctl_wstep, sdbc_wctl_wfini },
3127 	{ "sdbc_wrq", "walk the write ctl queue (free list)",
3128 		sdbc_wrq_winit, sdbc_wrq_wstep, sdbc_wrq_wfini },
3129 #endif /* SAFESTORE */
3130 	/* others */
3131 	{ "sdbc_cdinfo",
3132 	    "walk the _sd_cache_files array of cache descriptor information",
3133 		sdbc_cdinfo_winit, sdbc_cdinfo_wstep, sdbc_cdinfo_wfini },
3134 #ifdef SAFESTORE
3135 	{ "sdbc_ftctl",
3136 	    "walk the allocated array of fault tolerant structures",
3137 		sdbc_ftctl_winit, sdbc_ftctl_wstep, sdbc_ftctl_wfini },
3138 #endif /* SAFESTORE */
3139 	{ "sdbc_handles", "walk array of _sd_buf_handle_t structures",
3140 		sdbc_handle_winit, sdbc_handle_wstep, sdbc_handle_wfini },
3141 
3142 	/* walkers for metadata arrays */
3143 	{ "sdbc_glcinfo", "walk the allocated global cache entry info array",
3144 		sdbc_glcinfo_winit, sdbc_glcinfo_wstep, sdbc_glcinfo_wfini },
3145 	{ "sdbc_glfinfo", "walk the allocated global file info array",
3146 		sdbc_glfinfo_winit, sdbc_glfinfo_wstep, sdbc_glfinfo_wfini },
3147 	{ NULL }
3148 };
3149 
3150 static const mdb_modinfo_t modinfo = {
3151 	MDB_API_VERSION, dcmds, walkers
3152 };
3153 
3154 const mdb_modinfo_t *
3155 _mdb_init(void)
3156 {
3157 	return (&modinfo);
3158 }
3159