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.
26 #pragma ident "%Z%%M% %I% %E% SMI"
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>
44 #include <sys/types.h>
45 #include <sys/mdb_modapi.h>
47 #define FT(var, typ) (*((typ *)(&(var))))
49 static int dump_states(uintptr_t array_vaddr
, int verbose
,
50 struct i_ddi_soft_state
*sp
);
51 static int i_vhci_states(uintptr_t addr
, uint_t flags
, int argc
,
52 const mdb_arg_t
*argv
, struct i_ddi_soft_state
*sp
);
53 static int vhci_states(uintptr_t addr
, uint_t flags
, int argc
,
54 const mdb_arg_t
*argv
);
56 static int mdiclient(uintptr_t addr
, uint_t flags
, int argc
,
57 const mdb_arg_t
*argv
);
58 static int vhciguid(uintptr_t addr
, uint_t flags
, int argc
,
59 const mdb_arg_t
*argv
);
60 static int vhcilun(uintptr_t addr
, uint_t flags
, int argc
,
61 const mdb_arg_t
*argv
);
62 static int i_vhcilun(uintptr_t addr
, uint_t display_single_guid
, char *guid
);
65 static int get_mdbstr(uintptr_t addr
, char *name
);
66 static void dump_mutex(kmutex_t m
, char *name
);
67 static void dump_condvar(kcondvar_t c
, char *name
);
68 static void dump_string(uintptr_t addr
, char *name
);
69 static void dump_flags(unsigned long long flags
, char **strings
);
70 static void dump_state_str(char *name
, uintptr_t addr
, char **strings
);
72 static int mpxio_walk_cb(uintptr_t addr
, const void *data
, void *cbdata
);
74 static const mdb_dcmd_t dcmds
[] = {
75 { "vhci_states", "[ -v ]", "dump all the vhci state pointers",
77 { "vhciguid", NULL
, "list all clients or given a guid, list one client",
82 static const mdb_modinfo_t modinfo
= {
83 MDB_API_VERSION
, dcmds
, NULL
86 static char *client_lb_str
[] =
94 static char *mdi_client_states
[] =
103 static char *client_flags
[] =
105 "MDI_CLIENT_FLAGS_OFFLINE",
106 "MDI_CLIENT_FLAGS_SUSPEND",
107 "MDI_CLIENT_FLAGS_POWER_DOWN",
108 "MDI_CLIENT_FLAGS_DETACH",
109 "MDI_CLIENT_FLAGS_FAILOVER",
110 "MDI_CLIENT_FLAGS_REPORT_DEV",
111 "MDI_CLIENT_FLAGS_PATH_FREE_IN_PROGRESS",
112 "MDI_CLIENT_FLAGS_ASYNC_FREE",
113 "MDI_CLIENT_FLAGS_DEV_NOT_SUPPORTED",
117 static char *vhci_conf_flags
[] =
119 "VHCI_CONF_FLAGS_AUTO_FAILBACK",
123 static char *svlun_flags
[] =
125 "VLUN_TASK_D_ALIVE_FLG",
126 "VLUN_RESERVE_ACTIVE_FLG",
131 static char mdipathinfo_cb_str
[] = "::print struct mdi_pathinfo";
133 const mdb_modinfo_t
*
142 * Dump mdi_client_t info and list all paths.
146 mdiclient(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
148 struct mdi_client value
;
150 if (!(flags
& DCMD_ADDRSPEC
)) {
151 mdb_warn("mdiclient: requires an address");
155 if (mdb_vread(&value
, sizeof (struct mdi_client
), addr
)
156 != sizeof (struct mdi_client
)) {
157 mdb_warn("mdiclient: Failed read on %l#r\n", addr
);
160 mdb_printf("----------------- mdi_client @ %#lr ----------\n", addr
);
161 dump_string((uintptr_t)value
.ct_guid
, "GUID (ct_guid)");
162 dump_string((uintptr_t)value
.ct_drvname
, "Driver Name (ct_drvname)");
163 dump_state_str("Load Balance (ct_lb)", value
.ct_lb
, client_lb_str
);
165 mdb_printf("ct_hnext: %26l#r::print struct mdi_client\n",
167 mdb_printf("ct_hprev: %26l#r::print struct mdi_client\n",
169 mdb_printf("ct_dip: %28l#r::print struct dev_info\n", value
.ct_dip
);
170 mdb_printf("ct_vhci: %27l#r::print struct mdi_vhci\n", value
.ct_vhci
);
171 mdb_printf("ct_cprivate: %23l#r\n", value
.ct_cprivate
);
172 mdb_printf("\nct_path_head: %22l#r::print struct mdi_pathinfo\n",
174 mdb_printf("ct_path_tail: %22l#r::print struct mdi_pathinfo\n",
176 mdb_printf("ct_path_last: %22l#r::print struct mdi_pathfinfo\n",
178 mdb_printf("ct_path_count: %21d\n", value
.ct_path_count
);
179 mdb_printf("List of paths:\n");
180 mdb_pwalk("mdipi_client_list", (mdb_walk_cb_t
)mpxio_walk_cb
,
181 mdipathinfo_cb_str
, (uintptr_t)value
.ct_path_head
);
184 dump_state_str("Client State (ct_state)", value
.ct_state
,
186 dump_mutex(value
.ct_mutex
, "per-client mutex (ct_mutex):");
187 mdb_printf("ct_flags: %26d\n", value
.ct_flags
);
188 if (value
.ct_flags
) {
189 dump_flags((unsigned long long)value
.ct_flags
, client_flags
);
191 mdb_printf("ct_unstable: %23d\n", value
.ct_unstable
);
192 dump_condvar(value
.ct_unstable_cv
, "ct_unstable_cv");
193 dump_condvar(value
.ct_failover_cv
, "ct_failover_cv");
196 mdb_printf("ct_failover_flags TEMP_VAR: %8d\n", value
.ct_failover_flags
)
198 mdb_printf("ct_failover_status UNUSED: %9d\n", value
.ct_failover_status
)
207 * Get client info given a guid.
211 vhcilun(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
213 if (!(flags
& DCMD_ADDRSPEC
)) {
214 mdb_warn("sv_lun: requires an address");
218 return (i_vhcilun(addr
, 0 /* display_single_guid */, 0));
224 * List all the clients.
228 vhciguid(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
231 struct i_ddi_soft_state ss
;
234 mdi_vhci_t
*mdi_vhci_value
;
235 mdi_client_t
*mdi_client_value
;
236 struct client_hash
*ct_hash_val
;
237 struct client_hash
*ct_hash_table_val
;
239 int len
= strlen(MDI_HCI_CLASS_SCSI
);
240 int mdi_vhci_len
= sizeof (*mdi_vhci_value
);
241 int mdi_client_len
= sizeof (*mdi_client_value
);
242 int ct_hash_len
= sizeof (*ct_hash_val
);
244 int ct_hash_count
= 0;
252 if (flags
& DCMD_ADDRSPEC
)
253 mdb_warn("This command doesn't use an address\n");
255 if (i_vhci_states(0, 0, 0, 0, &ss
) != DCMD_OK
)
258 if (mdb_readvar(&buf
, "mdi_vhci_head") == -1) {
259 mdb_warn("mdi driver variable mdi_vhci_head not found.\n");
260 mdb_warn("Is the driver loaded ?\n");
263 mdb_printf("----------------- mdi_vhci_head @ %#lr ----------\n", buf
);
264 mdi_vhci_value
= (mdi_vhci_t
*)mdb_alloc(mdi_vhci_len
, UM_SLEEP
|UM_GC
);
265 if (mdb_vread(mdi_vhci_value
, mdi_vhci_len
, buf
) != mdi_vhci_len
) {
266 mdb_warn("vhciguid: Failed read on %l#r\n", mdi_vhci_value
);
267 mdb_free(mdi_vhci_value
, mdi_vhci_len
);
270 temp
= (uintptr_t)mdi_vhci_value
->vh_class
;
271 class = (char *)mdb_alloc(len
, UM_SLEEP
|UM_GC
);
272 if (mdb_vread(class, strlen(MDI_HCI_CLASS_SCSI
), temp
)
273 != strlen(MDI_HCI_CLASS_SCSI
)) {
274 mdb_warn("vhciguid: Failed read of class %l#r\n",
276 mdb_free(mdi_vhci_value
, mdi_vhci_len
);
277 mdb_free(class, len
);
281 mdb_printf("----------------- class @ %s----------\n", class);
283 if (strcmp(class, MDI_HCI_CLASS_SCSI
) == 0) {
287 if (mdi_vhci_value
->vh_next
== NULL
) {
290 temp
= (uintptr_t)mdi_vhci_value
->vh_next
;
291 if (mdb_vread(mdi_vhci_value
, mdi_vhci_len
, temp
)
293 mdb_warn("vhciguid: Failed read on vh->next %l#r\n",
297 temp
= (uintptr_t)mdi_vhci_value
->vh_class
;
298 if (mdb_vread(class, strlen(MDI_HCI_CLASS_SCSI
), temp
) !=
299 strlen(MDI_HCI_CLASS_SCSI
)) {
300 mdb_warn("vhciguid: Failed read on vh->next %l#r\n",
308 mdb_warn("vhciguid: No scsi_vhci class found");
309 mdb_free(mdi_vhci_value
, mdi_vhci_len
);
310 mdb_free(class, len
);
313 mdb_printf("----- Number of devices found %d ----------\n",
314 mdi_vhci_value
->vh_client_count
);
315 for (i
= 0; i
< CLIENT_HASH_TABLE_SIZE
; i
++) {
316 ct_hash_table_val
= &mdi_vhci_value
->vh_client_table
[i
];
317 if (ct_hash_table_val
== NULL
)
320 /* Read client_hash structure */
321 ct_hash_val
= (struct client_hash
*)mdb_alloc(ct_hash_len
,
323 temp
= (uintptr_t)ct_hash_table_val
;
324 if (mdb_vread(ct_hash_val
, ct_hash_len
, temp
) != ct_hash_len
) {
325 mdb_warn("Failed read on hash %l#r\n",
329 mdb_printf("----hash[%d] %l#r: devices mapped = %d --\n",
330 i
, ct_hash_table_val
, ct_hash_val
->ct_hash_count
);
331 if (ct_hash_val
->ct_hash_count
== 0) {
335 ct_hash_count
= ct_hash_val
->ct_hash_count
;
337 /* Read mdi_client structures */
338 mdi_client_value
= (mdi_client_t
*)mdb_alloc(mdi_client_len
,
340 temp
= (uintptr_t)ct_hash_val
->ct_hash_head
;
341 if (mdb_vread(mdi_client_value
, mdi_client_len
, temp
)
343 mdb_warn("Failed read on client %l#r\n",
347 mdb_printf("mdi_client %l#r %l#r ------\n",
348 mdi_client_value
, mdi_client_value
->ct_vprivate
);
349 vhcilun((uintptr_t)mdi_client_value
->ct_vprivate
,
350 DCMD_ADDRSPEC
, 0, 0);
352 while (--ct_hash_count
) {
353 temp
= (uintptr_t)mdi_client_value
->ct_hnext
;
354 if (mdb_vread(mdi_client_value
, mdi_client_len
,
355 temp
) != mdi_client_len
) {
356 mdb_warn("Failed read on client %l#r\n",
360 vhcilun((uintptr_t)mdi_client_value
->ct_vprivate
,
361 DCMD_ADDRSPEC
, 0, 0);
364 mdb_printf("----------done----------\n");
370 * Print the flag name by comparing flags to the mask variable.
373 dump_flags(unsigned long long flags
, char **strings
)
375 int i
, linel
= 8, first
= 1;
376 unsigned long long mask
= 1;
378 for (i
= 0; i
< 64; i
++) {
379 if (strings
[i
] == NULL
)
387 /* make output pretty */
388 linel
+= strlen(strings
[i
]) + 3;
391 linel
= strlen(strings
[i
]) + 1 + 8;
393 mdb_printf("%s", strings
[i
]);
402 vhci_states(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
404 return (i_vhci_states(addr
, flags
, argc
, argv
, NULL
));
410 * Print the state information for vhci_states().
413 dump_states(uintptr_t array_vaddr
, int verbose
, struct i_ddi_soft_state
*sp
)
417 struct i_ddi_soft_state
*ss
;
418 struct scsi_vhci vhci
;
421 ss
= (struct i_ddi_soft_state
*)mdb_alloc(sizeof (*ss
),
426 if (mdb_vread(ss
, sizeof (*ss
), array_vaddr
) != sizeof (*ss
)) {
427 mdb_warn("Cannot read softstate struct (Invalid pointer?).\n");
430 array_size
= ss
->n_items
* (sizeof (void *));
431 array_vaddr
= (uintptr_t)ss
->array
;
432 ss
->array
= mdb_alloc(array_size
, UM_SLEEP
|UM_GC
);
433 if (mdb_vread(ss
->array
, array_size
, array_vaddr
) != array_size
) {
434 mdb_warn("Corrupted softstate struct.\n");
441 * ss->size is of type size_t which is 4 bytes and 8 bytes
442 * on 32-bit and 64-bit systems respectively.
445 mdb_printf("Softstate size is %lld(0x%llx) bytes.\n\n",
448 mdb_printf("Softstate size is %ld(0x%lx) bytes.\n\n",
451 mdb_printf("state pointer\t\t\t\t\tinstance\n");
452 mdb_printf("=============\t\t\t\t\t========\n");
454 for (i
= 0; i
< ss
->n_items
; i
++) {
455 if (ss
->array
[i
] == 0)
458 if (mdb_vread(&vhci
, sizeof (vhci
), (uintptr_t)ss
->array
[i
])
460 mdb_warn("Corrupted softstate struct.\n");
464 mdb_printf("%l#r::print struct scsi_vhci\t\t %d\n",
466 mdb_printf("\nvhci_conf_flags: %d\n",
467 vhci
.vhci_conf_flags
);
468 if (vhci
.vhci_conf_flags
) {
470 dump_flags((unsigned long long)
471 vhci
.vhci_conf_flags
, vhci_conf_flags
);
474 mdb_printf("%l#r\n", ss
->array
[i
]);
481 get_mdbstr(uintptr_t addr
, char *string_val
)
483 if (mdb_readstr(string_val
, MAXNAMELEN
, addr
) == -1) {
484 mdb_warn("Error Reading String from %l#r\n", addr
);
492 dump_state_str(char *name
, uintptr_t addr
, char **strings
)
494 mdb_printf("%s: %s (%l#r)\n", name
, strings
[(unsigned long)addr
], addr
);
502 * Internal routine for vhci_states() to check for -v arg and then
507 i_vhci_states(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
,
508 struct i_ddi_soft_state
*sp
)
513 if (mdb_readvar(&adr
, "vhci_softstate") == -1) {
514 mdb_warn("vhci driver variable vhci_softstate not found.\n");
515 mdb_warn("Is the driver loaded ?\n");
519 if (mdb_getopts(argc
, argv
,
520 'v', MDB_OPT_SETBITS
, TRUE
, &verbose
) != argc
) {
525 return (dump_states(adr
, verbose
, sp
));
531 * Internal routine for vhciguid() to print client info.
534 i_vhcilun(uintptr_t addr
, uint_t display_single_guid
, char *guid
)
537 scsi_vhci_lun_t value
;
538 struct dev_info dev_info_value
;
539 char string_val
[MAXNAMELEN
];
541 struct mdi_client ct_value
;
545 if (mdb_vread(&value
, sizeof (scsi_vhci_lun_t
), addr
) !=
546 sizeof (scsi_vhci_lun_t
)) {
547 mdb_warn("sv_lun: Failed read on %l#r", addr
);
552 addr
= (uintptr_t)value
.svl_hash_next
;
554 if (!get_mdbstr((uintptr_t)value
.svl_lun_wwn
, string_val
)) {
555 if (display_single_guid
) {
556 if (strcmp(string_val
, guid
) == 0) {
562 mdb_printf("%t%l#r::print struct scsi_vhci_lun", temp_addr
);
564 if (mdb_vread(&dev_info_value
, sizeof (struct dev_info
),
565 (uintptr_t)value
.svl_dip
) != sizeof (struct dev_info
)) {
566 mdb_warn("svl_dip: Failed read on %l#r",
571 mdb_printf("\n%tGUID: %s\n", string_val
);
572 if (value
.svl_active_pclass
!= NULL
) {
573 if (!get_mdbstr((uintptr_t)value
.svl_active_pclass
,
575 mdb_printf("%tActv_cl: %s", string_val
);
578 mdb_printf(" No active pclass");
580 if (display_single_guid
) {
581 mdb_printf(" (%l#r)", value
.svl_active_pclass
);
584 mdb_printf("\n%t%l#r::print struct mdi_client",
585 dev_info_value
.devi_mdi_client
);
587 if (value
.svl_flags
) {
589 dump_flags((unsigned long long)value
.svl_flags
,
596 mdiclient((uintptr_t)dev_info_value
.devi_mdi_client
,
597 DCMD_ADDRSPEC
, 0, 0);
599 if (mdb_vread(&ct_value
, sizeof (struct mdi_client
),
600 (uintptr_t)dev_info_value
.devi_mdi_client
) !=
601 sizeof (struct mdi_client
)) {
602 mdb_warn("mdiclient: Failed read on %l#r",
603 dev_info_value
.devi_mdi_client
);
606 if (ct_value
.ct_flags
) {
608 dump_flags((unsigned long long)
609 ct_value
.ct_flags
, client_flags
);
612 dump_state_str("LB", ct_value
.ct_lb
, client_lb_str
);
615 } while (addr
&& !found
);
620 dump_mutex(kmutex_t m
, char *name
)
622 mdb_printf("%s is%s held\n", name
, FT(m
, uint64_t) == 0 ? " not" : "");
626 dump_condvar(kcondvar_t c
, char *name
)
628 mdb_printf("Threads sleeping on %s = %d\n", name
, (int)FT(c
, ushort_t
));
632 dump_string(uintptr_t addr
, char *name
)
634 char string_val
[MAXNAMELEN
];
636 if (get_mdbstr(addr
, string_val
)) {
639 mdb_printf("%s: %s (%l#r)\n", name
, string_val
, addr
);
644 mpxio_walk_cb(uintptr_t addr
, const void *data
, void *cbdata
)
646 mdb_printf("%t%l#r%s\n", addr
, (char *)cbdata
);