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.
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.
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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <sys/types.h>
27 #include <sys/mdb_modapi.h>
29 #include <sys/sunddi.h>
30 #include <sys/sunldi.h>
32 #include <sys/nsctl/nsctl.h>
33 #include <sys/unistat/spcs_s.h>
34 #include <sys/unistat/spcs_s_k.h>
36 #include <sys/nsctl/sv.h>
37 #include <sys/nsctl/sv_impl.h>
39 #include <sys/nsctl/nsvers.h>
42 * Walker for an array of sv_dev_t structures.
43 * A global walk is assumed to start at sv_devs.
53 sv_dev_winit(mdb_walk_state_t
*wsp
)
55 struct sv_dev_winfo
*winfo
;
59 winfo
= mdb_zalloc(sizeof (struct sv_dev_winfo
), UM_SLEEP
);
61 if (mdb_readvar(&sv_devs
, "sv_devs") == -1) {
62 mdb_warn("failed to read 'sv_devs'");
63 mdb_free(winfo
, sizeof (struct sv_dev_winfo
));
67 if (mdb_readvar(&sv_max_devices
, "sv_max_devices") == -1) {
68 mdb_warn("failed to read 'sv_max_devices'");
69 mdb_free(winfo
, sizeof (struct sv_dev_winfo
));
73 winfo
->start
= (uintptr_t)sv_devs
;
74 winfo
->end
= (uintptr_t)(sv_devs
+ sv_max_devices
);
76 if (wsp
->walk_addr
== NULL
)
77 wsp
->walk_addr
= winfo
->start
;
79 wsp
->walk_data
= winfo
;
85 sv_dev_wstep(mdb_walk_state_t
*wsp
)
87 struct sv_dev_winfo
*winfo
= wsp
->walk_data
;
90 if (wsp
->walk_addr
== NULL
)
93 if (wsp
->walk_addr
>= winfo
->end
)
96 status
= wsp
->walk_callback(wsp
->walk_addr
, wsp
->walk_data
,
99 wsp
->walk_addr
+= sizeof (sv_dev_t
);
105 sv_dev_wfini(mdb_walk_state_t
*wsp
)
107 mdb_free(wsp
->walk_data
, sizeof (struct sv_dev_winfo
));
112 * Walker for an sv hash chain.
113 * Global walks are disallowed.
117 sv_hash_winit(mdb_walk_state_t
*wsp
)
119 if (wsp
->walk_addr
== NULL
)
122 wsp
->walk_data
= mdb_zalloc(sizeof (sv_dev_t
), UM_SLEEP
);
129 sv_hash_wstep(mdb_walk_state_t
*wsp
)
133 if (wsp
->walk_addr
== NULL
)
136 if (mdb_vread(wsp
->walk_data
,
137 sizeof (sv_dev_t
), wsp
->walk_addr
) == -1) {
138 mdb_warn("failed to read sv_dev at %p", wsp
->walk_addr
);
142 status
= wsp
->walk_callback(wsp
->walk_addr
, wsp
->walk_data
,
145 wsp
->walk_addr
= (uintptr_t)(((sv_dev_t
*)wsp
->walk_data
)->sv_hash
);
151 sv_hash_wfini(mdb_walk_state_t
*wsp
)
153 mdb_free(wsp
->walk_data
, sizeof (sv_dev_t
));
158 * Walker for an array of sv_maj_t structures.
159 * A global walk is assumed to start at sv_majors.
162 sv_maj_t
*sv_majors
[SV_MAJOR_HASH_CNT
+ 1] = {0};
165 sv_maj_winit(mdb_walk_state_t
*wsp
)
167 if (wsp
->walk_addr
== NULL
) {
168 if (mdb_readvar(&sv_majors
, "sv_majors") == -1) {
169 mdb_warn("failed to read 'sv_majors'");
173 sv_majors
[0] = (sv_maj_t
*)wsp
->walk_addr
;
176 wsp
->walk_addr
= (uintptr_t)&sv_majors
[0];
177 wsp
->walk_data
= mdb_zalloc(sizeof (sv_maj_t
), UM_SLEEP
);
184 sv_maj_wstep(mdb_walk_state_t
*wsp
)
187 int status
= DCMD_OK
;
189 if (wsp
->walk_addr
== NULL
)
192 if (wsp
->walk_addr
>= (uintptr_t)&sv_majors
[SV_MAJOR_HASH_CNT
])
195 for (addr
= *(uintptr_t *)wsp
->walk_addr
; addr
;
196 addr
= (uintptr_t)(((sv_maj_t
*)wsp
->walk_data
)->sm_next
)) {
198 if (mdb_vread(wsp
->walk_data
, sizeof (sv_maj_t
), addr
)
199 != sizeof (sv_maj_t
)) {
200 mdb_warn("failed to read sv_maj at %p", addr
);
205 status
= wsp
->walk_callback(addr
, wsp
->walk_data
,
207 if (status
!= DCMD_OK
)
211 wsp
->walk_addr
+= sizeof (sv_maj_t
*);
217 sv_maj_wfini(mdb_walk_state_t
*wsp
)
219 mdb_free(wsp
->walk_data
, sizeof (sv_maj_t
));
224 * Walker for an sv gclient chain.
225 * A global walk is assumed to start at sv_gclients.
229 sv_gclient_winit(mdb_walk_state_t
*wsp
)
231 if (wsp
->walk_addr
== NULL
&&
232 mdb_readvar(&wsp
->walk_addr
, "sv_gclients") == -1) {
233 mdb_warn("unable to read 'sv_gclients'");
237 wsp
->walk_data
= mdb_zalloc(sizeof (sv_gclient_t
), UM_SLEEP
);
244 sv_gclient_wstep(mdb_walk_state_t
*wsp
)
248 if (wsp
->walk_addr
== NULL
)
251 if (mdb_vread(wsp
->walk_data
,
252 sizeof (sv_gclient_t
), wsp
->walk_addr
) == -1) {
253 mdb_warn("failed to read sv_gclient at %p", wsp
->walk_addr
);
257 status
= wsp
->walk_callback(wsp
->walk_addr
, wsp
->walk_data
,
260 wsp
->walk_addr
= (uintptr_t)(((sv_gclient_t
*)wsp
->walk_data
)->sg_next
);
266 sv_gclient_wfini(mdb_walk_state_t
*wsp
)
268 mdb_free(wsp
->walk_data
, sizeof (sv_gclient_t
));
273 * Display a single sv_glcient_t structure.
274 * If called with no address, performs a global walk of all sv_gclients.
277 sv_gclient(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
285 if (!(flags
& DCMD_ADDRSPEC
)) {
287 * paranoid mode on: qualify walker name with module name
290 if (mdb_walk_dcmd("sv`sv_gclient",
291 "sv`sv_gclient", argc
, argv
) == -1) {
292 mdb_warn("failed to walk 'sv_gclient'");
298 if (mdb_vread(&sg
, sizeof (sg
), addr
) != sizeof (sg
)) {
299 mdb_warn("failed to read sv_gclient at %p", addr
);
303 if (DCMD_HDRSPEC(flags
)) {
304 mdb_printf("%-?s %8T%-?s %8T%-16s %8T%s\n",
305 "ADDR", "NEXT", "ID", "NAME");
308 if (mdb_readstr(name
, sizeof (name
), (uintptr_t)sg
.sg_name
) == -1) {
309 mdb_warn("failed to read sv_gclient name at %p", addr
);
313 mdb_printf("%p %8T%p %8T%llx %8T%s",
314 addr
, sg
.sg_next
, sg
.sg_id
, name
);
321 * Display a single sv_maj_t structure.
322 * If called with no address, performs a global walk of all sv_majs.
323 * -a : all (i.e. display all devices, even if disabled
327 sv_maj(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
333 a_opt
= v_opt
= FALSE
;
335 if (mdb_getopts(argc
, argv
,
336 'a', MDB_OPT_SETBITS
, TRUE
, &a_opt
,
337 'v', MDB_OPT_SETBITS
, TRUE
, &v_opt
) != argc
)
340 if (!(flags
& DCMD_ADDRSPEC
)) {
342 * paranoid mode on: qualify walker name with module name
345 if (mdb_walk_dcmd("sv`sv_maj", "sv`sv_maj", argc
, argv
) == -1) {
346 mdb_warn("failed to walk 'sv_maj'");
352 if (DCMD_HDRSPEC(flags
)) {
353 mdb_printf("%-?s %8T%s\n", "ADDR", "INUSE");
356 maj
= mdb_zalloc(sizeof (*maj
), UM_GC
);
357 if (mdb_vread(maj
, sizeof (*maj
), addr
) != sizeof (*maj
)) {
358 mdb_warn("failed to read sv_maj at %p", addr
);
362 if (!a_opt
&& maj
->sm_inuse
== 0)
365 mdb_printf("%?p %8T%d\n", addr
, maj
->sm_inuse
);
371 * verbose - print the rest of the structure as well.
377 mdb_printf("dev_ops: %a (%p)\n", maj
->sm_dev_ops
, maj
->sm_dev_ops
);
378 mdb_printf("flag: %08x %8Tsequence: %d %8Tmajor: %d\n",
379 maj
->sm_flag
, maj
->sm_seq
, maj
->sm_major
);
381 mdb_printf("function pointers:\n");
383 mdb_printf("%-20a%-20a%\n%-20a%-20a%\n%-20a%-20a%\n%-20a%-20a%\n",
384 maj
->sm_open
, maj
->sm_close
,
385 maj
->sm_read
, maj
->sm_write
,
386 maj
->sm_aread
, maj
->sm_awrite
,
387 maj
->sm_strategy
, maj
->sm_ioctl
);
391 mdb_printf("hash chain:\n");
393 for (i
= 0; i
< SV_MINOR_HASH_CNT
; i
++) {
394 mdb_printf("%?p", maj
->sm_hash
[i
]);
395 mdb_printf(((i
% 4) == 3) ? "\n" : " %8T");
405 * Display a sv_dev_t hash chain.
406 * Requires an address.
407 * Same options as sv_dev().
410 sv_hash(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
412 if (!(flags
& DCMD_ADDRSPEC
))
416 * paranoid mode on: qualify walker name with module name
419 if (mdb_pwalk_dcmd("sv`sv_hash", "sv`sv_dev", argc
, argv
, addr
) == -1) {
420 mdb_warn("failed to walk sv_dev hash chain");
429 * Display a single sv_dev_t structure.
430 * If called with no address, performs a global walk of all sv_devs.
431 * -a : all (i.e. display all devices, even if disabled
435 const mdb_bitmask_t sv_flag_bits
[] = {
436 { "NSC_DEVICE", NSC_DEVICE
, NSC_DEVICE
},
437 { "NSC_CACHE", NSC_CACHE
, NSC_CACHE
},
442 sv_dev(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
448 a_opt
= v_opt
= FALSE
;
449 dev_t_chars
= sizeof (dev_t
) * 2; /* # chars to display dev_t */
451 if (mdb_getopts(argc
, argv
,
452 'a', MDB_OPT_SETBITS
, TRUE
, &a_opt
,
453 'v', MDB_OPT_SETBITS
, TRUE
, &v_opt
) != argc
)
456 svp
= mdb_zalloc(sizeof (*svp
), UM_GC
);
458 if (!(flags
& DCMD_ADDRSPEC
)) {
460 * paranoid mode on: qualify walker name with module name
463 if (mdb_walk_dcmd("sv`sv_dev", "sv`sv_dev", argc
, argv
) == -1) {
464 mdb_warn("failed to walk 'sv_dev'");
470 if (DCMD_HDRSPEC(flags
)) {
471 mdb_printf("%-?s %8T%-*s %8T%s\n", "ADDR",
472 dev_t_chars
, "DEV", "STATE");
475 if (mdb_vread(svp
, sizeof (*svp
), addr
) != sizeof (*svp
)) {
476 mdb_warn("failed to read sv_dev at %p", addr
);
480 if (!a_opt
&& svp
->sv_state
== SV_DISABLE
)
483 mdb_printf("%?p %8T%0*lx %8T", addr
, dev_t_chars
, svp
->sv_dev
);
485 if (svp
->sv_state
== SV_DISABLE
)
486 mdb_printf("disabled");
487 else if (svp
->sv_state
== SV_PENDING
)
488 mdb_printf("pending");
489 else if (svp
->sv_state
== SV_ENABLE
)
490 mdb_printf("enabled");
498 * verbose - print the rest of the structure as well.
504 mdb_printf("hash chain: 0x%p %8Tlock: 0x%p %8Tolock: 0x%p\n",
506 addr
+ OFFSETOF(sv_dev_t
, sv_lock
),
507 addr
+ OFFSETOF(sv_dev_t
, sv_olock
));
509 mdb_printf("fd: 0x%p %8T\n", svp
->sv_fd
);
511 mdb_printf("maxfbas: %d %8Tnblocks: %d %8Tstate: %d\n",
512 svp
->sv_maxfbas
, svp
->sv_nblocks
, svp
->sv_state
);
514 mdb_printf("gclients: 0x%llx %8Tgkernel: 0x%llx\n",
515 svp
->sv_gclients
, svp
->sv_gkernel
);
517 mdb_printf("openlcnt: %d %8Ttimestamp: 0x%lx\n",
518 svp
->sv_openlcnt
, svp
->sv_timestamp
);
520 mdb_printf("flags: 0x%08x <%b>\n",
521 svp
->sv_flag
, svp
->sv_flag
, sv_flag_bits
);
523 mdb_printf("lh: 0x%p %8Tpending: 0x%p\n",
524 svp
->sv_lh
, svp
->sv_pending
);
532 * Display general sv module information.
535 #define sv_get_print(kvar, str, fmt, val) \
536 if (mdb_readvar(&(val), #kvar) == -1) { \
538 mdb_warn("unable to read '" #kvar "'"); \
541 mdb_printf("%-20s" fmt "\n", str ":", val)
545 sv(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
548 int maj
, min
, mic
, baseline
, i
;
553 if (mdb_readvar(&maj
, "sv_major_rev") == -1) {
554 mdb_warn("unable to read 'sv_major_rev'");
558 if (mdb_readvar(&min
, "sv_minor_rev") == -1) {
559 mdb_warn("unable to read 'sv_minor_rev'");
563 if (mdb_readvar(&mic
, "sv_micro_rev") == -1) {
564 mdb_warn("unable to read 'sv_micro_rev'");
568 if (mdb_readvar(&baseline
, "sv_baseline_rev") == -1) {
569 mdb_warn("unable to read 'sv_baseline_rev'");
573 mdb_printf("SV module version: kernel %d.%d.%d.%d; mdb %d.%d.%d.%d\n",
574 maj
, min
, mic
, baseline
,
575 ISS_VERSION_MAJ
, ISS_VERSION_MIN
, ISS_VERSION_MIC
, ISS_VERSION_NUM
);
578 sv_get_print(sv_config_time
, "last config time", "0x%lx", clock
);
579 sv_get_print(sv_stats_on
, "stats on", "%d", i
);
580 sv_get_print(sv_debug
, "debug", "%d", i
);
581 sv_get_print(sv_max_devices
, "max sv devices", "%d", i
);
589 * MDB module linkage information:
592 static const mdb_dcmd_t dcmds
[] = {
593 { "sv", NULL
, "display sv module info", sv
},
594 { "sv_dev", "?[-av]", "list sv_dev structure", sv_dev
},
595 { "sv_gclient", "?", "list sv_gclient structure", sv_gclient
},
596 { "sv_hash", ":[-av]", "display sv_dev hash chain", sv_hash
},
597 { "sv_maj", "?[-av]", "list sv_maj structure", sv_maj
},
602 static const mdb_walker_t walkers
[] = {
603 { "sv_dev", "walk array of sv_dev structures",
604 sv_dev_winit
, sv_dev_wstep
, sv_dev_wfini
},
605 { "sv_gclient", "walk sb_gclient chain",
606 sv_gclient_winit
, sv_gclient_wstep
, sv_gclient_wfini
},
607 { "sv_hash", "walk sv_dev hash chain",
608 sv_hash_winit
, sv_hash_wstep
, sv_hash_wfini
},
609 { "sv_maj", "walk array of sv_maj structures",
610 sv_maj_winit
, sv_maj_wstep
, sv_maj_wfini
},
615 static const mdb_modinfo_t modinfo
= {
616 MDB_API_VERSION
, dcmds
, walkers
620 const mdb_modinfo_t
*