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 }