xref: /illumos-gate/usr/src/cmd/mdb/common/modules/genunix/mdi.c (revision 20a7641f9918de8574b8b3b47dbe35c4bfc78df1)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <sys/kmem.h>
27 #include <sys/proc.h>
28 #include <sys/time.h>
29 #include <sys/conf.h>
30 #include <sys/file.h>
31 #include <sys/ddi.h>
32 #include <sys/ddi_impldefs.h>
33 #include <sys/modctl.h>
34 #include <sys/sunddi.h>
35 #include <sys/scsi/scsi.h>
36 #include <sys/scsi/impl/scsi_reset_notify.h>
37 #include <sys/sunmdi.h>
38 #include <sys/mdi_impldefs.h>
39 #include <sys/scsi/adapters/scsi_vhci.h>
40 #include <sys/scsi/scsi_types.h>
41 #include <sys/disp.h>
42 #include <sys/types.h>
43 #include <sys/mdb_modapi.h>
44 #include "mdi.h"
45 
46 #define	FT(var, typ)	(*((typ *)(&(var))))
47 
48 /* Utils */
49 static int get_mdbstr(uintptr_t addr, char *name);
50 static void dump_flags(unsigned long long flags, char **strings);
51 static void dump_mutex(kmutex_t m, char *name);
52 static void dump_condvar(kcondvar_t c, char *name);
53 static void dump_string(uintptr_t addr, char *name);
54 static void dump_state_str(char *name, uintptr_t addr, char **strings);
55 
56 static int mpxio_walk_cb(uintptr_t addr, const void *data, void *cbdata);
57 
58 static char *client_lb_str[] =
59 {
60 	"NONE",
61 	"RR",
62 	"LBA",
63 	NULL
64 };
65 
66 static char *mdi_pathinfo_states[] =
67 {
68 	"MDI_PATHINFO_STATE_INIT",
69 	"MDI_PATHINFO_STATE_ONLINE",
70 	"MDI_PATHINFO_STATE_STANDBY",
71 	"MDI_PATHINFO_STATE_FAULT",
72 	"MDI_PATHINFO_STATE_OFFLINE",
73 	NULL
74 };
75 
76 static char *mdi_pathinfo_ext_states[] =
77 {
78 	"MDI_PATHINFO_STATE_USER_DISABLE",
79 	"MDI_PATHINFO_STATE_DRV_DISABLE",
80 	"MDI_PATHINFO_STATE_DRV_DISABLE_TRANSIENT",
81 	NULL
82 };
83 
84 static char *mdi_phci_flags[] =
85 {
86 	"MDI_PHCI_FLAGS_OFFLINE",
87 	"MDI_PHCI_FLAGS_SUSPEND",
88 	"MDI_PHCI_FLAGS_POWER_DOWN",
89 	"MDI_PHCI_FLAGS_DETACH",
90 	"MDI_PHCI_FLAGS_USER_DISABLE",
91 	"MDI_PHCI_FLAGS_D_DISABLE",
92 	"MDI_PHCI_FLAGS_D_DISABLE_TRANS",
93 	"MDI_PHCI_FLAGS_POWER_TRANSITION",
94 	NULL
95 };
96 
97 static uintptr_t firstaddr = 0;
98 static char mdipathinfo_cb_str[] = "::print struct mdi_pathinfo";
99 static char mdiphci_cb_str[] = "::print struct mdi_phci";
100 
101 /*
102  * mdipi()
103  *
104  * Given a path, dump mdi_pathinfo struct and detailed pi_prop list.
105  */
106 /* ARGSUSED */
107 int
108 mdipi(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
109 {
110 	struct mdi_pathinfo	value;
111 
112 	if (!(flags & DCMD_ADDRSPEC)) {
113 		mdb_warn("mdipi: requires an address");
114 		return (DCMD_ERR);
115 	}
116 
117 	if (mdb_vread(&value, sizeof (struct mdi_pathinfo), addr) !=
118 	    sizeof (struct mdi_pathinfo)) {
119 		mdb_warn("mdipi: Failed read on %l#r\n", addr);
120 		return (DCMD_ERR);
121 	}
122 	mdb_printf("------------- mdi_pathinfo @ %#lr ----------\n", addr);
123 
124 	dump_string((uintptr_t)value.pi_addr, "PWWN,LUN (pi_addr)");
125 
126 	mdb_printf("\n");
127 	mdb_printf("pi_client: %25l#r::print struct mdi_client\n",
128 	    value.pi_client);
129 	mdb_printf("pi_phci: %27l#r::print struct mdi_phci\n", value.pi_phci);
130 	mdb_printf("pi_pprivate: %23l#r\n", value.pi_pprivate);
131 	mdb_printf("pi_client_link: %20l#r::print struct mdi_pathinfo\n",
132 	    value.pi_client_link);
133 	mdb_printf("pi_phci_link: %22l#r::print struct mdi_pathinfo\n",
134 	    value.pi_phci_link);
135 	mdb_printf("pi_prop: %27l#r::print struct nv_list\n", value.pi_prop);
136 
137 	mdiprops((uintptr_t)value.pi_prop, flags, 0, NULL);
138 
139 	mdb_printf("\n");
140 	dump_state_str("Pathinfo State (pi_state)        ",
141 	    MDI_PI_STATE(&value), mdi_pathinfo_states);
142 	if (MDI_PI_IS_TRANSIENT(&value)) {
143 		mdb_printf("Pathinfo State is TRANSIENT\n");
144 	}
145 	if (MDI_PI_EXT_STATE(&value)) {
146 		mdb_printf("      Extended (pi_state)        : ");
147 		/*
148 		 * Need to shift right 20 bits to match mdi_pathinfo_ext_states
149 		 * array.
150 		 */
151 		dump_flags((unsigned long long)MDI_PI_EXT_STATE(&value) >> 20,
152 		    mdi_pathinfo_ext_states);
153 	}
154 	dump_state_str("Old Pathinfo State (pi_old_state)",
155 	    MDI_PI_OLD_STATE(&value), mdi_pathinfo_states);
156 	if (MDI_PI_OLD_EXT_STATE(&value)) {
157 		mdb_printf("      Extended (pi_old_state)    : ");
158 		/*
159 		 * Need to shift right 20 bits to match mdi_pathinfo_ext_states
160 		 * array.
161 		 */
162 		dump_flags((unsigned long long)MDI_PI_OLD_EXT_STATE(&value)
163 		>> 20, mdi_pathinfo_ext_states);
164 	}
165 	dump_mutex(value.pi_mutex, "per-path mutex (pi_mutex):");
166 	dump_condvar(value.pi_state_cv, "Path state (pi_state_cv)");
167 
168 	mdb_printf("\n");
169 	mdb_printf("pi_ref_cnt: %d\n", value.pi_ref_cnt);
170 	dump_condvar(value.pi_ref_cv, "pi_ref_cv");
171 
172 	mdb_printf("\n");
173 	mdb_printf("pi_kstats: %25l#r::print struct mdi_pi_kstats\n",
174 	    value.pi_kstats);
175 	mdb_printf("pi_cprivate UNUSED: %16l#r \n", value.pi_cprivate);
176 
177 	return (DCMD_OK);
178 }
179 
180 /*
181  * mdiprops()
182  *
183  * Given a pi_prop, dump the pi_prop list.
184  */
185 /* ARGSUSED */
186 int
187 mdiprops(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
188 {
189 	if (!(flags & DCMD_ADDRSPEC)) {
190 		mdb_warn("mdiprops: requires an address");
191 		return (DCMD_ERR);
192 	}
193 
194 	mdb_printf("\tnvpairs @ %#lr:\n", addr);
195 	mdb_pwalk_dcmd("nvpair", "nvpair", argc, argv, addr);
196 	mdb_printf("\n");
197 
198 	return (DCMD_OK);
199 }
200 
201 /*
202  * mdiphci()
203  *
204  * Given a phci, dump mdi_phci struct.
205  */
206 /* ARGSUSED */
207 int
208 mdiphci(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
209 {
210 	struct mdi_phci value;
211 
212 	if (!(flags & DCMD_ADDRSPEC)) {
213 		mdb_warn("mdiphci: requires an address");
214 		return (DCMD_ERR);
215 	}
216 
217 	if (mdb_vread(&value, sizeof (struct mdi_phci), addr) !=
218 	    sizeof (struct mdi_phci)) {
219 		mdb_warn("mdiphci: Failed read on %l#r\n", addr);
220 		return (DCMD_ERR);
221 	}
222 	mdb_printf("---------------- mdi_phci @ %#lr ----------\n", addr);
223 
224 	mdb_printf("ph_next: %27l#r::print struct mdi_phci\n", value.ph_next);
225 	mdb_printf("ph_prev: %27l#r::print struct mdi_phci\n", value.ph_prev);
226 	mdb_printf("ph_vhci: %27l#r::print struct mdi_vhci\n", value.ph_vhci);
227 	mdb_printf("ph_dip: %28l#r::print struct dev_info\n", value.ph_dip);
228 	mdb_printf("\nph_path_head: %22l#r::print struct mdi_pathinfo\n",
229 	    value.ph_path_head);
230 	mdb_printf("ph_path_tail: %22l#r::print struct mdi_pathinfo\n",
231 	    value.ph_path_tail);
232 	mdb_printf("ph_path_count: %21d\n", value.ph_path_count);
233 	mdb_printf("List of paths:\n");
234 	mdb_pwalk("mdipi_phci_list", (mdb_walk_cb_t)mpxio_walk_cb,
235 			mdipathinfo_cb_str, (uintptr_t)value.ph_path_head);
236 
237 	mdb_printf("\n");
238 	mdb_printf("ph_flags: %26d\n", value.ph_flags);
239 	if (value.ph_flags) {
240 		dump_flags((unsigned long long)value.ph_flags, mdi_phci_flags);
241 	}
242 	dump_mutex(value.ph_mutex, "per-pHCI mutex (ph_mutex):");
243 	dump_condvar(value.ph_unstable_cv,
244 	    "Paths in transient state (ph_unstable_cv)");
245 	mdb_printf("ph_unstable: %23d\n", value.ph_unstable);
246 
247 	return (DCMD_OK);
248 }
249 
250 /*
251  * mdivhci()
252  *
253  * Given a vhci, dump mdi_vhci struct and list all phcis.
254  */
255 /* ARGSUSED */
256 int
257 mdivhci(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
258 {
259 	struct mdi_vhci value;
260 
261 	if (!(flags & DCMD_ADDRSPEC)) {
262 		mdb_warn("mdivhci: requires an address");
263 		return (DCMD_ERR);
264 	}
265 
266 	if (mdb_vread(&value, sizeof (struct mdi_vhci), addr) !=
267 	    sizeof (struct mdi_vhci)) {
268 		mdb_warn("mdivhci: Failed read on %l#r\n", addr);
269 		return (DCMD_ERR);
270 	}
271 	mdb_printf("----------------- mdi_vhci @ %#lr ----------\n", addr);
272 
273 	dump_string((uintptr_t)value.vh_class, "Class name (vh_class)");
274 	mdb_printf("vh_refcnt: %19d\n", value.vh_refcnt);
275 	mdb_printf("vh_dip: %28l#r::print struct dev_info\n", value.vh_dip);
276 	mdb_printf("vh_next: %27l#r::print struct mdi_vhci\n", value.vh_next);
277 	mdb_printf("vh_prev: %27l#r::print struct mdi_vhci\n", value.vh_prev);
278 	dump_state_str("Load Balance (vh_lb)", value.vh_lb, client_lb_str);
279 	mdb_printf("vh_ops: %28l#r::print struct mdi_vhci_ops\n",
280 	    value.vh_ops);
281 
282 	dump_mutex(value.vh_phci_mutex, "phci mutex (vh_phci_mutex):");
283 	mdb_printf("vh_phci_count: %21d\n", value.vh_phci_count);
284 	mdb_printf("\nvh_phci_head: %22l#r::print struct mdi_phci\n",
285 	    value.vh_phci_head);
286 	mdb_printf("vh_phci_tail: %22l#r::print struct mdi_phci\n",
287 	    value.vh_phci_tail);
288 
289 	dump_mutex(value.vh_phci_mutex, "client mutex (vh_client_mutex):");
290 	mdb_printf("vh_client_count: %19d\n", value.vh_client_count);
291 	mdb_printf("vh_client_table: %19l#r::print struct client_hash\n",
292 	    value.vh_client_table);
293 
294 	mdb_printf("List of pHCIs:\n");
295 	mdb_pwalk("mdiphci_list", (mdb_walk_cb_t)mpxio_walk_cb,
296 			mdiphci_cb_str, (uintptr_t)value.vh_phci_head);
297 	mdb_printf("\n");
298 	return (DCMD_OK);
299 }
300 
301 /* mdi_pathinfo client walker */
302 
303 /* ARGUSED */
304 int
305 mdi_pi_client_link_walk_init(mdb_walk_state_t *wsp)
306 {
307 	if (wsp->walk_addr == 0) {
308 		mdb_warn("Address is required");
309 		return (WALK_ERR);
310 	}
311 	wsp->walk_data = mdb_alloc(sizeof (struct mdi_pathinfo), UM_SLEEP);
312 	firstaddr = wsp->walk_addr;
313 	return (WALK_NEXT);
314 }
315 
316 /* ARGUSED */
317 int
318 mdi_pi_client_link_walk_step(mdb_walk_state_t *wsp)
319 {
320 	int		status = 0;
321 	static int	counts = 0;
322 
323 	if (firstaddr == wsp->walk_addr && counts != 0) {
324 		counts = 0;
325 		return (WALK_DONE);
326 	}
327 	if (wsp->walk_addr == 0) {
328 		counts = 0;
329 		return (WALK_DONE);
330 	}
331 	if (mdb_vread(wsp->walk_data, sizeof (struct mdi_pathinfo),
332 	    wsp->walk_addr) == -1) {
333 		mdb_warn("failed to read mdi_pathinfo at %p", wsp->walk_addr);
334 		return (WALK_DONE);
335 	}
336 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
337 	    wsp->walk_cbdata);
338 	wsp->walk_addr = (uintptr_t)
339 	    (((struct mdi_pathinfo *)wsp->walk_data)->pi_client_link);
340 	counts++;
341 	return (status);
342 }
343 
344 /* ARGUSED */
345 void
346 mdi_pi_client_link_walk_fini(mdb_walk_state_t *wsp)
347 {
348 	mdb_free(wsp->walk_data, sizeof (struct mdi_pathinfo));
349 }
350 
351 /*
352  * mdiclient_paths()
353  *
354  * Given a path, walk through mdi_pathinfo client links.
355  */
356 /* ARGUSED */
357 int
358 mdiclient_paths(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
359 {
360 	int status;
361 	if (argc != 0)
362 		return (DCMD_USAGE);
363 
364 	if (!(flags & DCMD_ADDRSPEC)) {
365 		mdb_warn("Address needs to be specified");
366 		return (DCMD_ERR);
367 	}
368 	status =
369 	    mdb_pwalk_dcmd("mdipi_client_list", "mdipi", argc, argv, addr);
370 	return (status);
371 }
372 
373 /* mdi_pathinfo phci walker */
374 int
375 mdi_pi_phci_link_walk_init(mdb_walk_state_t *wsp)
376 {
377 	if (wsp->walk_addr == 0) {
378 		mdb_warn("Address is required");
379 		return (WALK_ERR);
380 	}
381 	wsp->walk_data = mdb_alloc(sizeof (struct mdi_pathinfo), UM_SLEEP);
382 	firstaddr = wsp->walk_addr;
383 	return (WALK_NEXT);
384 }
385 
386 int
387 mdi_pi_phci_link_walk_step(mdb_walk_state_t *wsp)
388 {
389 	int status;
390 	static int	counts = 0;
391 
392 	if (firstaddr == wsp->walk_addr && counts != 0) {
393 		counts = 0;
394 		return (WALK_DONE);
395 	}
396 	if (wsp->walk_addr == 0) {
397 		counts = 0;
398 		return (WALK_DONE);
399 	}
400 	if (mdb_vread(wsp->walk_data, sizeof (struct mdi_pathinfo),
401 	    wsp->walk_addr) == -1) {
402 		mdb_warn("failed to read mdi_pathinfo at %p", wsp->walk_addr);
403 		return (WALK_DONE);
404 	}
405 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
406 	    wsp->walk_cbdata);
407 	wsp->walk_addr = (uintptr_t)
408 	    (((struct mdi_pathinfo *)wsp->walk_data)->pi_phci_link);
409 	counts++;
410 	return (status);
411 }
412 
413 void
414 mdi_pi_phci_link_walk_fini(mdb_walk_state_t *wsp)
415 {
416 	mdb_free(wsp->walk_data, sizeof (struct mdi_pathinfo));
417 }
418 
419 /*
420  * mdiphci_paths()
421  *
422  * Given a path, walk through mdi_pathinfo phci links.
423  */
424 int
425 mdiphci_paths(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
426 {
427 	int status;
428 	if (argc != 0)
429 		return (DCMD_USAGE);
430 
431 	if (!(flags & DCMD_ADDRSPEC)) {
432 		mdb_warn("Address needs to be specified");
433 		return (DCMD_ERR);
434 	}
435 	status =
436 	    mdb_pwalk_dcmd("mdipi_phci_list", "mdipi", argc, argv, addr);
437 	return (status);
438 }
439 
440 /* mdi_phci walker */
441 int
442 mdi_phci_ph_next_walk_init(mdb_walk_state_t *wsp)
443 {
444 	if (wsp->walk_addr == 0) {
445 		mdb_warn("Address is required");
446 		return (WALK_ERR);
447 	}
448 	wsp->walk_data = mdb_alloc(sizeof (struct mdi_phci), UM_SLEEP);
449 	firstaddr = wsp->walk_addr;
450 	return (WALK_NEXT);
451 }
452 
453 int
454 mdi_phci_ph_next_walk_step(mdb_walk_state_t *wsp)
455 {
456 	int status;
457 	static int counts = 0;
458 
459 	if (firstaddr == wsp->walk_addr && counts != 0) {
460 		counts = 0;
461 		return (WALK_DONE);
462 	}
463 	if (wsp->walk_addr == 0) {
464 		counts = 0;
465 		return (WALK_DONE);
466 	}
467 	if (mdb_vread(wsp->walk_data, sizeof (struct mdi_phci), wsp->walk_addr)
468 	    == -1) {
469 		mdb_warn("failed to read mdi_phci at %p", wsp->walk_addr);
470 		return (WALK_DONE);
471 	}
472 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
473 	    wsp->walk_cbdata);
474 	wsp->walk_addr = (uintptr_t)
475 	    (((struct mdi_phci *)wsp->walk_data)->ph_next);
476 	counts++;
477 	return (status);
478 }
479 
480 void
481 mdi_phci_ph_next_walk_fini(mdb_walk_state_t *wsp)
482 {
483 	mdb_free(wsp->walk_data, sizeof (struct mdi_phci));
484 }
485 
486 /*
487  * mdiphcis()
488  *
489  * Given a phci, walk through mdi_phci ph_next links.
490  */
491 int
492 mdiphcis(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
493 {
494 	int status;
495 	if (argc != 0)
496 		return (DCMD_USAGE);
497 
498 	if (!(flags & DCMD_ADDRSPEC)) {
499 		mdb_warn("Address needs to be specified");
500 		return (DCMD_ERR);
501 	}
502 	status =
503 	    mdb_pwalk_dcmd("mdiphci_list", "mdiphci", argc, argv, addr);
504 	return (status);
505 }
506 
507 /*
508  * Print the flag name by comparing flags to the mask variable.
509  */
510 static void
511 dump_flags(unsigned long long flags, char **strings)
512 {
513 	int i, linel = 8, first = 1;
514 	unsigned long long mask = 1;
515 
516 	for (i = 0; i < 64; i++) {
517 		if (strings[i] == NULL)
518 			break;
519 		if (flags & mask) {
520 			if (!first) {
521 				mdb_printf(" | ");
522 			} else {
523 				first = 0;
524 			}
525 			/* make output pretty */
526 			linel += strlen(strings[i]) + 3;
527 			if (linel > 80) {
528 				mdb_printf("\n\t");
529 				linel = strlen(strings[i]) + 1 + 8;
530 			}
531 			mdb_printf("%s", strings[i]);
532 		}
533 		mask <<= 1;
534 	}
535 	mdb_printf("\n");
536 }
537 
538 static void
539 dump_mutex(kmutex_t m, char *name)
540 {
541 	mdb_printf("%s is%s held\n", name, FT(m, uint64_t) == 0 ? " not" : "");
542 }
543 
544 static void
545 dump_condvar(kcondvar_t c, char *name)
546 {
547 	mdb_printf("Threads sleeping on %s = %d\n", name, (int)FT(c, ushort_t));
548 }
549 
550 static int
551 get_mdbstr(uintptr_t addr, char *string_val)
552 {
553 	if (mdb_readstr(string_val, MAXNAMELEN, addr) == -1) {
554 		mdb_warn("Error Reading String from %l#r\n", addr);
555 		return (1);
556 	}
557 
558 	return (0);
559 }
560 
561 static void
562 dump_string(uintptr_t addr, char *name)
563 {
564 	char string_val[MAXNAMELEN];
565 
566 	if (get_mdbstr(addr, string_val)) {
567 		return;
568 	}
569 	mdb_printf("%s: %s (%l#r)\n", name, string_val, addr);
570 }
571 
572 static void
573 dump_state_str(char *name, uintptr_t addr, char **strings)
574 {
575 	mdb_printf("%s: %s (%l#r)\n", name, strings[(unsigned long)addr], addr);
576 }
577 
578 /* ARGSUSED */
579 static int
580 mpxio_walk_cb(uintptr_t addr, const void *data, void *cbdata)
581 {
582 	mdb_printf("%t%l#r%s\n", addr, (char *)cbdata);
583 	return (0);
584 }
585