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