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
mdipi(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
mdiprops(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
mdiphci(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
mdivhci(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
mdi_pi_client_link_walk_init(mdb_walk_state_t * wsp)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
mdi_pi_client_link_walk_step(mdb_walk_state_t * wsp)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
mdi_pi_client_link_walk_fini(mdb_walk_state_t * wsp)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
mdiclient_paths(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
mdi_pi_phci_link_walk_init(mdb_walk_state_t * wsp)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
mdi_pi_phci_link_walk_step(mdb_walk_state_t * wsp)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
mdi_pi_phci_link_walk_fini(mdb_walk_state_t * wsp)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
mdiphci_paths(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
mdi_phci_ph_next_walk_init(mdb_walk_state_t * wsp)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
mdi_phci_ph_next_walk_step(mdb_walk_state_t * wsp)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
mdi_phci_ph_next_walk_fini(mdb_walk_state_t * wsp)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
mdiphcis(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
dump_flags(unsigned long long flags,char ** strings)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
dump_mutex(kmutex_t m,char * name)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
dump_condvar(kcondvar_t c,char * name)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
get_mdbstr(uintptr_t addr,char * string_val)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
dump_string(uintptr_t addr,char * name)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
dump_state_str(char * name,uintptr_t addr,char ** strings)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
mpxio_walk_cb(uintptr_t addr,const void * data,void * cbdata)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