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 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
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>
42 #include <sys/types.h>
43 #include <sys/mdb_modapi.h>
46 #define FT(var, typ) (*((typ *)(&(var))))
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
);
56 static int mpxio_walk_cb(uintptr_t addr
, const void *data
, void *cbdata
);
58 static char *client_lb_str
[] =
66 static char *mdi_pathinfo_states
[] =
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",
76 static char *mdi_pathinfo_ext_states
[] =
78 "MDI_PATHINFO_STATE_USER_DISABLE",
79 "MDI_PATHINFO_STATE_DRV_DISABLE",
80 "MDI_PATHINFO_STATE_DRV_DISABLE_TRANSIENT",
84 static char *mdi_phci_flags
[] =
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",
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";
104 * Given a path, dump mdi_pathinfo struct and detailed pi_prop list.
108 mdipi(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
110 struct mdi_pathinfo value
;
112 if (!(flags
& DCMD_ADDRSPEC
)) {
113 mdb_warn("mdipi: requires an address");
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
);
122 mdb_printf("------------- mdi_pathinfo @ %#lr ----------\n", addr
);
124 dump_string((uintptr_t)value
.pi_addr
, "PWWN,LUN (pi_addr)");
127 mdb_printf("pi_client: %25l#r::print struct mdi_client\n",
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",
135 mdb_printf("pi_prop: %27l#r::print struct nv_list\n", value
.pi_prop
);
137 mdiprops((uintptr_t)value
.pi_prop
, flags
, 0, NULL
);
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");
145 if (MDI_PI_EXT_STATE(&value
)) {
146 mdb_printf(" Extended (pi_state) : ");
148 * Need to shift right 20 bits to match mdi_pathinfo_ext_states
151 dump_flags((unsigned long long)MDI_PI_EXT_STATE(&value
) >> 20,
152 mdi_pathinfo_ext_states
);
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) : ");
159 * Need to shift right 20 bits to match mdi_pathinfo_ext_states
162 dump_flags((unsigned long long)MDI_PI_OLD_EXT_STATE(&value
)
163 >> 20, mdi_pathinfo_ext_states
);
165 dump_mutex(value
.pi_mutex
, "per-path mutex (pi_mutex):");
166 dump_condvar(value
.pi_state_cv
, "Path state (pi_state_cv)");
169 mdb_printf("pi_ref_cnt: %d\n", value
.pi_ref_cnt
);
170 dump_condvar(value
.pi_ref_cv
, "pi_ref_cv");
173 mdb_printf("pi_kstats: %25l#r::print struct mdi_pi_kstats\n",
175 mdb_printf("pi_cprivate UNUSED: %16l#r \n", value
.pi_cprivate
);
183 * Given a pi_prop, dump the pi_prop list.
187 mdiprops(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
189 if (!(flags
& DCMD_ADDRSPEC
)) {
190 mdb_warn("mdiprops: requires an address");
194 mdb_printf("\tnvpairs @ %#lr:\n", addr
);
195 mdb_pwalk_dcmd("nvpair", "nvpair", argc
, argv
, addr
);
204 * Given a phci, dump mdi_phci struct.
208 mdiphci(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
210 struct mdi_phci value
;
212 if (!(flags
& DCMD_ADDRSPEC
)) {
213 mdb_warn("mdiphci: requires an address");
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
);
222 mdb_printf("---------------- mdi_phci @ %#lr ----------\n", addr
);
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",
230 mdb_printf("ph_path_tail: %22l#r::print struct mdi_pathinfo\n",
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
);
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
);
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
);
253 * Given a vhci, dump mdi_vhci struct and list all phcis.
257 mdivhci(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
259 struct mdi_vhci value
;
261 if (!(flags
& DCMD_ADDRSPEC
)) {
262 mdb_warn("mdivhci: requires an address");
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
);
271 mdb_printf("----------------- mdi_vhci @ %#lr ----------\n", addr
);
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",
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",
286 mdb_printf("vh_phci_tail: %22l#r::print struct mdi_phci\n",
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
);
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
);
301 /* mdi_pathinfo client walker */
305 mdi_pi_client_link_walk_init(mdb_walk_state_t
*wsp
)
307 if (wsp
->walk_addr
== (uintptr_t)NULL
) {
308 mdb_warn("Address is required");
311 wsp
->walk_data
= mdb_alloc(sizeof (struct mdi_pathinfo
), UM_SLEEP
);
312 firstaddr
= wsp
->walk_addr
;
318 mdi_pi_client_link_walk_step(mdb_walk_state_t
*wsp
)
321 static int counts
= 0;
323 if (firstaddr
== wsp
->walk_addr
&& counts
!= 0) {
327 if (wsp
->walk_addr
== (uintptr_t)NULL
) {
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
);
336 status
= wsp
->walk_callback(wsp
->walk_addr
, wsp
->walk_data
,
338 wsp
->walk_addr
= (uintptr_t)
339 (((struct mdi_pathinfo
*)wsp
->walk_data
)->pi_client_link
);
346 mdi_pi_client_link_walk_fini(mdb_walk_state_t
*wsp
)
348 mdb_free(wsp
->walk_data
, sizeof (struct mdi_pathinfo
));
354 * Given a path, walk through mdi_pathinfo client links.
358 mdiclient_paths(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
364 if (!(flags
& DCMD_ADDRSPEC
)) {
365 mdb_warn("Address needs to be specified");
369 mdb_pwalk_dcmd("mdipi_client_list", "mdipi", argc
, argv
, addr
);
373 /* mdi_pathinfo phci walker */
375 mdi_pi_phci_link_walk_init(mdb_walk_state_t
*wsp
)
377 if (wsp
->walk_addr
== (uintptr_t)NULL
) {
378 mdb_warn("Address is required");
381 wsp
->walk_data
= mdb_alloc(sizeof (struct mdi_pathinfo
), UM_SLEEP
);
382 firstaddr
= wsp
->walk_addr
;
387 mdi_pi_phci_link_walk_step(mdb_walk_state_t
*wsp
)
390 static int counts
= 0;
392 if (firstaddr
== wsp
->walk_addr
&& counts
!= 0) {
396 if (wsp
->walk_addr
== (uintptr_t)NULL
) {
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
);
405 status
= wsp
->walk_callback(wsp
->walk_addr
, wsp
->walk_data
,
407 wsp
->walk_addr
= (uintptr_t)
408 (((struct mdi_pathinfo
*)wsp
->walk_data
)->pi_phci_link
);
414 mdi_pi_phci_link_walk_fini(mdb_walk_state_t
*wsp
)
416 mdb_free(wsp
->walk_data
, sizeof (struct mdi_pathinfo
));
422 * Given a path, walk through mdi_pathinfo phci links.
425 mdiphci_paths(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
431 if (!(flags
& DCMD_ADDRSPEC
)) {
432 mdb_warn("Address needs to be specified");
436 mdb_pwalk_dcmd("mdipi_phci_list", "mdipi", argc
, argv
, addr
);
440 /* mdi_phci walker */
442 mdi_phci_ph_next_walk_init(mdb_walk_state_t
*wsp
)
444 if (wsp
->walk_addr
== (uintptr_t)NULL
) {
445 mdb_warn("Address is required");
448 wsp
->walk_data
= mdb_alloc(sizeof (struct mdi_phci
), UM_SLEEP
);
449 firstaddr
= wsp
->walk_addr
;
454 mdi_phci_ph_next_walk_step(mdb_walk_state_t
*wsp
)
457 static int counts
= 0;
459 if (firstaddr
== wsp
->walk_addr
&& counts
!= 0) {
463 if (wsp
->walk_addr
== (uintptr_t)NULL
) {
467 if (mdb_vread(wsp
->walk_data
, sizeof (struct mdi_phci
), wsp
->walk_addr
)
469 mdb_warn("failed to read mdi_phci at %p", wsp
->walk_addr
);
472 status
= wsp
->walk_callback(wsp
->walk_addr
, wsp
->walk_data
,
474 wsp
->walk_addr
= (uintptr_t)
475 (((struct mdi_phci
*)wsp
->walk_data
)->ph_next
);
481 mdi_phci_ph_next_walk_fini(mdb_walk_state_t
*wsp
)
483 mdb_free(wsp
->walk_data
, sizeof (struct mdi_phci
));
489 * Given a phci, walk through mdi_phci ph_next links.
492 mdiphcis(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
498 if (!(flags
& DCMD_ADDRSPEC
)) {
499 mdb_warn("Address needs to be specified");
503 mdb_pwalk_dcmd("mdiphci_list", "mdiphci", argc
, argv
, addr
);
508 * Print the flag name by comparing flags to the mask variable.
511 dump_flags(unsigned long long flags
, char **strings
)
513 int i
, linel
= 8, first
= 1;
514 unsigned long long mask
= 1;
516 for (i
= 0; i
< 64; i
++) {
517 if (strings
[i
] == NULL
)
525 /* make output pretty */
526 linel
+= strlen(strings
[i
]) + 3;
529 linel
= strlen(strings
[i
]) + 1 + 8;
531 mdb_printf("%s", strings
[i
]);
539 dump_mutex(kmutex_t m
, char *name
)
541 mdb_printf("%s is%s held\n", name
, FT(m
, uint64_t) == 0 ? " not" : "");
545 dump_condvar(kcondvar_t c
, char *name
)
547 mdb_printf("Threads sleeping on %s = %d\n", name
, (int)FT(c
, ushort_t
));
551 get_mdbstr(uintptr_t addr
, char *string_val
)
553 if (mdb_readstr(string_val
, MAXNAMELEN
, addr
) == -1) {
554 mdb_warn("Error Reading String from %l#r\n", addr
);
562 dump_string(uintptr_t addr
, char *name
)
564 char string_val
[MAXNAMELEN
];
566 if (get_mdbstr(addr
, string_val
)) {
569 mdb_printf("%s: %s (%l#r)\n", name
, string_val
, addr
);
573 dump_state_str(char *name
, uintptr_t addr
, char **strings
)
575 mdb_printf("%s: %s (%l#r)\n", name
, strings
[(unsigned long)addr
], addr
);
580 mpxio_walk_cb(uintptr_t addr
, const void *data
, void *cbdata
)
582 mdb_printf("%t%l#r%s\n", addr
, (char *)cbdata
);