xref: /titanic_41/usr/src/cmd/mdb/common/modules/sv/sv.c (revision fcf3ce441efd61da9bb2884968af01cb7c1452cc)
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/types.h>
27 #include <sys/mdb_modapi.h>
28 #include <sys/ddi.h>
29 #include <sys/sunddi.h>
30 #include <sys/sunldi.h>
31 
32 #include <sys/nsctl/nsctl.h>
33 #include <sys/unistat/spcs_s.h>
34 #include <sys/unistat/spcs_s_k.h>
35 
36 #include <sys/nsctl/sv.h>
37 #include <sys/nsctl/sv_impl.h>
38 
39 #include <sys/nsctl/nsvers.h>
40 
41 /*
42  * Walker for an array of sv_dev_t structures.
43  * A global walk is assumed to start at sv_devs.
44  */
45 
46 struct sv_dev_winfo {
47 	uintptr_t start;
48 	uintptr_t end;
49 };
50 
51 
52 static int
sv_dev_winit(mdb_walk_state_t * wsp)53 sv_dev_winit(mdb_walk_state_t *wsp)
54 {
55 	struct sv_dev_winfo *winfo;
56 	sv_dev_t *sv_devs;
57 	int sv_max_devices;
58 
59 	winfo = mdb_zalloc(sizeof (struct sv_dev_winfo), UM_SLEEP);
60 
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));
64 		return (WALK_ERR);
65 	}
66 
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));
70 		return (WALK_ERR);
71 	}
72 
73 	winfo->start = (uintptr_t)sv_devs;
74 	winfo->end = (uintptr_t)(sv_devs + sv_max_devices);
75 
76 	if (wsp->walk_addr == NULL)
77 		wsp->walk_addr = winfo->start;
78 
79 	wsp->walk_data = winfo;
80 	return (WALK_NEXT);
81 }
82 
83 
84 static int
sv_dev_wstep(mdb_walk_state_t * wsp)85 sv_dev_wstep(mdb_walk_state_t *wsp)
86 {
87 	struct sv_dev_winfo *winfo = wsp->walk_data;
88 	int status;
89 
90 	if (wsp->walk_addr == NULL)
91 		return (WALK_DONE);
92 
93 	if (wsp->walk_addr >= winfo->end)
94 		return (WALK_DONE);
95 
96 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
97 	    wsp->walk_cbdata);
98 
99 	wsp->walk_addr += sizeof (sv_dev_t);
100 	return (status);
101 }
102 
103 
104 static void
sv_dev_wfini(mdb_walk_state_t * wsp)105 sv_dev_wfini(mdb_walk_state_t *wsp)
106 {
107 	mdb_free(wsp->walk_data, sizeof (struct sv_dev_winfo));
108 }
109 
110 
111 /*
112  * Walker for an sv hash chain.
113  * Global walks are disallowed.
114  */
115 
116 static int
sv_hash_winit(mdb_walk_state_t * wsp)117 sv_hash_winit(mdb_walk_state_t *wsp)
118 {
119 	if (wsp->walk_addr == NULL)
120 		return (WALK_ERR);
121 
122 	wsp->walk_data = mdb_zalloc(sizeof (sv_dev_t), UM_SLEEP);
123 
124 	return (WALK_NEXT);
125 }
126 
127 
128 static int
sv_hash_wstep(mdb_walk_state_t * wsp)129 sv_hash_wstep(mdb_walk_state_t *wsp)
130 {
131 	int status;
132 
133 	if (wsp->walk_addr == NULL)
134 		return (WALK_DONE);
135 
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);
139 		return (WALK_DONE);
140 	}
141 
142 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
143 	    wsp->walk_cbdata);
144 
145 	wsp->walk_addr = (uintptr_t)(((sv_dev_t *)wsp->walk_data)->sv_hash);
146 	return (status);
147 }
148 
149 
150 static void
sv_hash_wfini(mdb_walk_state_t * wsp)151 sv_hash_wfini(mdb_walk_state_t *wsp)
152 {
153 	mdb_free(wsp->walk_data, sizeof (sv_dev_t));
154 }
155 
156 
157 /*
158  * Walker for an array of sv_maj_t structures.
159  * A global walk is assumed to start at sv_majors.
160  */
161 
162 sv_maj_t *sv_majors[SV_MAJOR_HASH_CNT + 1] = {0};
163 
164 static int
sv_maj_winit(mdb_walk_state_t * wsp)165 sv_maj_winit(mdb_walk_state_t *wsp)
166 {
167 	if (wsp->walk_addr == NULL) {
168 		if (mdb_readvar(&sv_majors, "sv_majors") == -1) {
169 			mdb_warn("failed to read 'sv_majors'");
170 			return (WALK_ERR);
171 		}
172 	} else {
173 		sv_majors[0] = (sv_maj_t *)wsp->walk_addr;
174 	}
175 
176 	wsp->walk_addr = (uintptr_t)&sv_majors[0];
177 	wsp->walk_data = mdb_zalloc(sizeof (sv_maj_t), UM_SLEEP);
178 
179 	return (WALK_NEXT);
180 }
181 
182 
183 static int
sv_maj_wstep(mdb_walk_state_t * wsp)184 sv_maj_wstep(mdb_walk_state_t *wsp)
185 {
186 	uintptr_t addr;
187 	int status = DCMD_OK;
188 
189 	if (wsp->walk_addr == NULL)
190 		return (WALK_DONE);
191 
192 	if (wsp->walk_addr >= (uintptr_t)&sv_majors[SV_MAJOR_HASH_CNT])
193 		return (WALK_DONE);
194 
195 	for (addr = *(uintptr_t *)wsp->walk_addr; addr;
196 		addr = (uintptr_t)(((sv_maj_t *)wsp->walk_data)->sm_next)) {
197 
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);
201 			status = DCMD_ERR;
202 			break;
203 		}
204 
205 		status = wsp->walk_callback(addr, wsp->walk_data,
206 						wsp->walk_cbdata);
207 		if (status != DCMD_OK)
208 			break;
209 	}
210 
211 	wsp->walk_addr += sizeof (sv_maj_t *);
212 	return (status);
213 }
214 
215 
216 static void
sv_maj_wfini(mdb_walk_state_t * wsp)217 sv_maj_wfini(mdb_walk_state_t *wsp)
218 {
219 	mdb_free(wsp->walk_data, sizeof (sv_maj_t));
220 }
221 
222 
223 /*
224  * Walker for an sv gclient chain.
225  * A global walk is assumed to start at sv_gclients.
226  */
227 
228 static int
sv_gclient_winit(mdb_walk_state_t * wsp)229 sv_gclient_winit(mdb_walk_state_t *wsp)
230 {
231 	if (wsp->walk_addr == NULL &&
232 	    mdb_readvar(&wsp->walk_addr, "sv_gclients") == -1) {
233 		mdb_warn("unable to read 'sv_gclients'");
234 		return (WALK_ERR);
235 	}
236 
237 	wsp->walk_data = mdb_zalloc(sizeof (sv_gclient_t), UM_SLEEP);
238 
239 	return (WALK_NEXT);
240 }
241 
242 
243 static int
sv_gclient_wstep(mdb_walk_state_t * wsp)244 sv_gclient_wstep(mdb_walk_state_t *wsp)
245 {
246 	int status;
247 
248 	if (wsp->walk_addr == NULL)
249 		return (WALK_DONE);
250 
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);
254 		return (WALK_DONE);
255 	}
256 
257 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
258 	    wsp->walk_cbdata);
259 
260 	wsp->walk_addr = (uintptr_t)(((sv_gclient_t *)wsp->walk_data)->sg_next);
261 	return (status);
262 }
263 
264 
265 static void
sv_gclient_wfini(mdb_walk_state_t * wsp)266 sv_gclient_wfini(mdb_walk_state_t *wsp)
267 {
268 	mdb_free(wsp->walk_data, sizeof (sv_gclient_t));
269 }
270 
271 
272 /*
273  * Display a single sv_glcient_t structure.
274  * If called with no address, performs a global walk of all sv_gclients.
275  */
276 static int
sv_gclient(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)277 sv_gclient(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
278 {
279 	sv_gclient_t sg;
280 	char name[64];
281 
282 	if (argc != 0)
283 		return (DCMD_USAGE);
284 
285 	if (!(flags & DCMD_ADDRSPEC)) {
286 		/*
287 		 * paranoid mode on: qualify walker name with module name
288 		 * using '`' syntax.
289 		 */
290 		if (mdb_walk_dcmd("sv`sv_gclient",
291 		    "sv`sv_gclient", argc, argv) == -1) {
292 			mdb_warn("failed to walk 'sv_gclient'");
293 			return (DCMD_ERR);
294 		}
295 		return (DCMD_OK);
296 	}
297 
298 	if (mdb_vread(&sg, sizeof (sg), addr) != sizeof (sg)) {
299 		mdb_warn("failed to read sv_gclient at %p", addr);
300 		return (DCMD_ERR);
301 	}
302 
303 	if (DCMD_HDRSPEC(flags)) {
304 		mdb_printf("%-?s  %8T%-?s  %8T%-16s  %8T%s\n",
305 		    "ADDR", "NEXT", "ID", "NAME");
306 	}
307 
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);
310 		return (DCMD_ERR);
311 	}
312 
313 	mdb_printf("%p  %8T%p  %8T%llx  %8T%s",
314 	    addr, sg.sg_next, sg.sg_id, name);
315 
316 	return (DCMD_OK);
317 }
318 
319 
320 /*
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
324  * -v : verbose
325  */
326 static int
sv_maj(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)327 sv_maj(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
328 {
329 	sv_maj_t *maj;
330 	int a_opt, v_opt;
331 	int i;
332 
333 	a_opt = v_opt = FALSE;
334 
335 	if (mdb_getopts(argc, argv,
336 	    'a', MDB_OPT_SETBITS, TRUE, &a_opt,
337 	    'v', MDB_OPT_SETBITS, TRUE, &v_opt) != argc)
338 		return (DCMD_USAGE);
339 
340 	if (!(flags & DCMD_ADDRSPEC)) {
341 		/*
342 		 * paranoid mode on: qualify walker name with module name
343 		 * using '`' syntax.
344 		 */
345 		if (mdb_walk_dcmd("sv`sv_maj", "sv`sv_maj", argc, argv) == -1) {
346 			mdb_warn("failed to walk 'sv_maj'");
347 			return (DCMD_ERR);
348 		}
349 		return (DCMD_OK);
350 	}
351 
352 	if (DCMD_HDRSPEC(flags)) {
353 		mdb_printf("%-?s  %8T%s\n", "ADDR", "INUSE");
354 	}
355 
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);
359 		return (DCMD_ERR);
360 	}
361 
362 	if (!a_opt && maj->sm_inuse == 0)
363 		return (DCMD_OK);
364 
365 	mdb_printf("%?p  %8T%d\n", addr, maj->sm_inuse);
366 
367 	if (!v_opt)
368 		return (DCMD_OK);
369 
370 	/*
371 	 * verbose - print the rest of the structure as well.
372 	 */
373 
374 	mdb_inc_indent(4);
375 	mdb_printf("\n");
376 
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);
380 
381 	mdb_printf("function pointers:\n");
382 	mdb_inc_indent(4);
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);
388 	mdb_dec_indent(4);
389 
390 
391 	mdb_printf("hash chain:\n");
392 	mdb_inc_indent(4);
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");
396 	}
397 	mdb_printf("\n\n");
398 	mdb_dec_indent(4);
399 	mdb_dec_indent(4);
400 	return (DCMD_OK);
401 }
402 
403 
404 /*
405  * Display a sv_dev_t hash chain.
406  * Requires an address.
407  * Same options as sv_dev().
408  */
409 static int
sv_hash(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)410 sv_hash(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
411 {
412 	if (!(flags & DCMD_ADDRSPEC))
413 		return (DCMD_USAGE);
414 
415 	/*
416 	 * paranoid mode on: qualify walker name with module name
417 	 * using '`' syntax.
418 	 */
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");
421 		return (DCMD_ERR);
422 	}
423 
424 	return (DCMD_OK);
425 }
426 
427 
428 /*
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
432  * -v : verbose
433  */
434 
435 const mdb_bitmask_t sv_flag_bits[] = {
436 	{ "NSC_DEVICE", NSC_DEVICE, NSC_DEVICE },
437 	{ "NSC_CACHE", NSC_CACHE, NSC_CACHE },
438 	{ NULL, 0, 0 }
439 };
440 
441 static int
sv_dev(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)442 sv_dev(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
443 {
444 	sv_dev_t *svp;
445 	int a_opt, v_opt;
446 	int dev_t_chars;
447 
448 	a_opt = v_opt = FALSE;
449 	dev_t_chars = sizeof (dev_t) * 2;	/* # chars to display dev_t */
450 
451 	if (mdb_getopts(argc, argv,
452 	    'a', MDB_OPT_SETBITS, TRUE, &a_opt,
453 	    'v', MDB_OPT_SETBITS, TRUE, &v_opt) != argc)
454 		return (DCMD_USAGE);
455 
456 	svp = mdb_zalloc(sizeof (*svp), UM_GC);
457 
458 	if (!(flags & DCMD_ADDRSPEC)) {
459 		/*
460 		 * paranoid mode on: qualify walker name with module name
461 		 * using '`' syntax.
462 		 */
463 		if (mdb_walk_dcmd("sv`sv_dev", "sv`sv_dev", argc, argv) == -1) {
464 			mdb_warn("failed to walk 'sv_dev'");
465 			return (DCMD_ERR);
466 		}
467 		return (DCMD_OK);
468 	}
469 
470 	if (DCMD_HDRSPEC(flags)) {
471 		mdb_printf("%-?s  %8T%-*s  %8T%s\n", "ADDR",
472 		    dev_t_chars, "DEV", "STATE");
473 	}
474 
475 	if (mdb_vread(svp, sizeof (*svp), addr) != sizeof (*svp)) {
476 		mdb_warn("failed to read sv_dev at %p", addr);
477 		return (DCMD_ERR);
478 	}
479 
480 	if (!a_opt && svp->sv_state == SV_DISABLE)
481 		return (DCMD_OK);
482 
483 	mdb_printf("%?p  %8T%0*lx  %8T", addr, dev_t_chars, svp->sv_dev);
484 
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");
491 
492 	mdb_printf("\n");
493 
494 	if (!v_opt)
495 		return (DCMD_OK);
496 
497 	/*
498 	 * verbose - print the rest of the structure as well.
499 	 */
500 
501 	mdb_inc_indent(4);
502 	mdb_printf("\n");
503 
504 	mdb_printf("hash chain: 0x%p  %8Tlock: 0x%p  %8Tolock: 0x%p\n",
505 	    svp->sv_hash,
506 	    addr + OFFSETOF(sv_dev_t, sv_lock),
507 	    addr + OFFSETOF(sv_dev_t, sv_olock));
508 
509 	mdb_printf("fd: 0x%p  %8T\n", svp->sv_fd);
510 
511 	mdb_printf("maxfbas: %d  %8Tnblocks: %d  %8Tstate: %d\n",
512 	    svp->sv_maxfbas, svp->sv_nblocks, svp->sv_state);
513 
514 	mdb_printf("gclients: 0x%llx  %8Tgkernel: 0x%llx\n",
515 	    svp->sv_gclients, svp->sv_gkernel);
516 
517 	mdb_printf("openlcnt: %d  %8Ttimestamp: 0x%lx\n",
518 	    svp->sv_openlcnt, svp->sv_timestamp);
519 
520 	mdb_printf("flags: 0x%08x <%b>\n",
521 	    svp->sv_flag, svp->sv_flag, sv_flag_bits);
522 
523 	mdb_printf("lh: 0x%p  %8Tpending: 0x%p\n",
524 	    svp->sv_lh, svp->sv_pending);
525 
526 	mdb_dec_indent(4);
527 	return (DCMD_OK);
528 }
529 
530 
531 /*
532  * Display general sv module information.
533  */
534 
535 #define	sv_get_print(kvar, str, fmt, val)		\
536 	if (mdb_readvar(&(val), #kvar) == -1) {		\
537 		mdb_dec_indent(4);			\
538 		mdb_warn("unable to read '" #kvar "'");	\
539 		return (DCMD_ERR);			\
540 	}						\
541 	mdb_printf("%-20s" fmt "\n", str ":", val)
542 
543 /* ARGSUSED */
544 static int
sv(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)545 sv(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
546 {
547 	clock_t clock;
548 	int maj, min, mic, baseline, i;
549 
550 	if (argc != 0)
551 		return (DCMD_USAGE);
552 
553 	if (mdb_readvar(&maj, "sv_major_rev") == -1) {
554 		mdb_warn("unable to read 'sv_major_rev'");
555 		return (DCMD_ERR);
556 	}
557 
558 	if (mdb_readvar(&min, "sv_minor_rev") == -1) {
559 		mdb_warn("unable to read 'sv_minor_rev'");
560 		return (DCMD_ERR);
561 	}
562 
563 	if (mdb_readvar(&mic, "sv_micro_rev") == -1) {
564 		mdb_warn("unable to read 'sv_micro_rev'");
565 		return (DCMD_ERR);
566 	}
567 
568 	if (mdb_readvar(&baseline, "sv_baseline_rev") == -1) {
569 		mdb_warn("unable to read 'sv_baseline_rev'");
570 		return (DCMD_ERR);
571 	}
572 
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);
576 	mdb_inc_indent(4);
577 
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);
582 
583 	mdb_dec_indent(4);
584 	return (DCMD_OK);
585 }
586 
587 
588 /*
589  * MDB module linkage information:
590  */
591 
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 },
598 	{ NULL }
599 };
600 
601 
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 },
611 	{ NULL }
612 };
613 
614 
615 static const mdb_modinfo_t modinfo = {
616 	MDB_API_VERSION, dcmds, walkers
617 };
618 
619 
620 const mdb_modinfo_t *
_mdb_init(void)621 _mdb_init(void)
622 {
623 	return (&modinfo);
624 }
625