170ab954aSramat /*
270ab954aSramat  * CDDL HEADER START
370ab954aSramat  *
470ab954aSramat  * The contents of this file are subject to the terms of the
570ab954aSramat  * Common Development and Distribution License (the "License").
670ab954aSramat  * You may not use this file except in compliance with the License.
770ab954aSramat  *
870ab954aSramat  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
970ab954aSramat  * or http://www.opensolaris.org/os/licensing.
1070ab954aSramat  * See the License for the specific language governing permissions
1170ab954aSramat  * and limitations under the License.
1270ab954aSramat  *
1370ab954aSramat  * When distributing Covered Code, include this CDDL HEADER in each
1470ab954aSramat  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1570ab954aSramat  * If applicable, add the following below this CDDL HEADER, with the
1670ab954aSramat  * fields enclosed by brackets "[]" replaced with your own identifying
1770ab954aSramat  * information: Portions Copyright [yyyy] [name of copyright owner]
1870ab954aSramat  *
1970ab954aSramat  * CDDL HEADER END
2070ab954aSramat  */
2170ab954aSramat /*
2270ab954aSramat  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
2370ab954aSramat  * Use is subject to license terms.
24*3b442230SJordan Paige Hendricks  *
25*3b442230SJordan Paige Hendricks  * Copyright 2019 Joyent, Inc.
2670ab954aSramat  */
2770ab954aSramat 
2870ab954aSramat #include <sys/kmem.h>
2970ab954aSramat #include <sys/proc.h>
3070ab954aSramat #include <sys/time.h>
3170ab954aSramat #include <sys/conf.h>
3270ab954aSramat #include <sys/file.h>
3370ab954aSramat #include <sys/ddi.h>
3470ab954aSramat #include <sys/ddi_impldefs.h>
3570ab954aSramat #include <sys/modctl.h>
3670ab954aSramat #include <sys/sunddi.h>
3770ab954aSramat #include <sys/scsi/scsi.h>
3870ab954aSramat #include <sys/scsi/impl/scsi_reset_notify.h>
3970ab954aSramat #include <sys/sunmdi.h>
4070ab954aSramat #include <sys/mdi_impldefs.h>
4170ab954aSramat #include <sys/scsi/adapters/scsi_vhci.h>
4270ab954aSramat #include <sys/scsi/scsi_types.h>
4370ab954aSramat #include <sys/disp.h>
4470ab954aSramat #include <sys/types.h>
4570ab954aSramat #include <sys/mdb_modapi.h>
4670ab954aSramat 
4770ab954aSramat #define	FT(var, typ)	(*((typ *)(&(var))))
4870ab954aSramat 
4970ab954aSramat static int dump_states(uintptr_t array_vaddr, int verbose,
5070ab954aSramat     struct i_ddi_soft_state *sp);
5170ab954aSramat static int i_vhci_states(uintptr_t addr, uint_t flags, int argc,
5270ab954aSramat     const mdb_arg_t *argv, struct i_ddi_soft_state *sp);
5370ab954aSramat static int vhci_states(uintptr_t addr, uint_t flags, int argc,
5470ab954aSramat     const mdb_arg_t *argv);
5570ab954aSramat 
5670ab954aSramat static int mdiclient(uintptr_t addr, uint_t flags, int argc,
5770ab954aSramat     const mdb_arg_t *argv);
5870ab954aSramat static int vhciguid(uintptr_t addr, uint_t flags, int argc,
5970ab954aSramat     const mdb_arg_t *argv);
6070ab954aSramat static int vhcilun(uintptr_t addr, uint_t flags, int argc,
6170ab954aSramat     const mdb_arg_t *argv);
6270ab954aSramat static int i_vhcilun(uintptr_t addr, uint_t display_single_guid, char *guid);
6370ab954aSramat 
6470ab954aSramat /* Utils */
6570ab954aSramat static int get_mdbstr(uintptr_t addr, char *name);
6670ab954aSramat static void dump_mutex(kmutex_t m, char *name);
6770ab954aSramat static void dump_condvar(kcondvar_t c, char *name);
6870ab954aSramat static void dump_string(uintptr_t addr, char *name);
6970ab954aSramat static void dump_flags(unsigned long long flags, char **strings);
7070ab954aSramat static void dump_state_str(char *name, uintptr_t addr, char **strings);
7170ab954aSramat 
7270ab954aSramat static int mpxio_walk_cb(uintptr_t addr, const void *data, void *cbdata);
7370ab954aSramat 
7470ab954aSramat static const mdb_dcmd_t dcmds[] = {
7570ab954aSramat 	{ "vhci_states", "[ -v ]", "dump all the vhci state pointers",
7670ab954aSramat 		vhci_states },
7770ab954aSramat 	{ "vhciguid", NULL, "list all clients or given a guid, list one client",
7870ab954aSramat 		vhciguid },
7970ab954aSramat 	{ NULL }
8070ab954aSramat };
8170ab954aSramat 
8270ab954aSramat static const mdb_modinfo_t modinfo = {
8370ab954aSramat 	MDB_API_VERSION, dcmds, NULL
8470ab954aSramat };
8570ab954aSramat 
8670ab954aSramat static char *client_lb_str[] =
8770ab954aSramat {
8870ab954aSramat 	"NONE",
8970ab954aSramat 	"RR",
9070ab954aSramat 	"LBA",
9170ab954aSramat 	NULL
9270ab954aSramat };
9370ab954aSramat 
9470ab954aSramat static char *mdi_client_states[] =
9570ab954aSramat {
9670ab954aSramat 	NULL,
9770ab954aSramat 	"OPTIMAL",
9870ab954aSramat 	"DEGRADED",
9970ab954aSramat 	"FAILED",
10070ab954aSramat 	NULL
10170ab954aSramat };
10270ab954aSramat 
10370ab954aSramat static char *client_flags[] =
10470ab954aSramat {
10570ab954aSramat 	"MDI_CLIENT_FLAGS_OFFLINE",
10670ab954aSramat 	"MDI_CLIENT_FLAGS_SUSPEND",
10770ab954aSramat 	"MDI_CLIENT_FLAGS_POWER_DOWN",
10870ab954aSramat 	"MDI_CLIENT_FLAGS_DETACH",
10970ab954aSramat 	"MDI_CLIENT_FLAGS_FAILOVER",
11070ab954aSramat 	"MDI_CLIENT_FLAGS_REPORT_DEV",
11170ab954aSramat 	"MDI_CLIENT_FLAGS_PATH_FREE_IN_PROGRESS",
11270ab954aSramat 	"MDI_CLIENT_FLAGS_ASYNC_FREE",
11370ab954aSramat 	"MDI_CLIENT_FLAGS_DEV_NOT_SUPPORTED",
11470ab954aSramat 	NULL
11570ab954aSramat };
11670ab954aSramat 
11770ab954aSramat static char *vhci_conf_flags[] =
11870ab954aSramat {
11970ab954aSramat 	"VHCI_CONF_FLAGS_AUTO_FAILBACK",
12070ab954aSramat 	NULL
12170ab954aSramat };
12270ab954aSramat 
12370ab954aSramat static char *svlun_flags[] =
12470ab954aSramat {
12570ab954aSramat 	"VLUN_TASK_D_ALIVE_FLG",
12670ab954aSramat 	"VLUN_RESERVE_ACTIVE_FLG",
12770ab954aSramat 	"VLUN_QUIESCED_FLG",
12870ab954aSramat 	NULL
12970ab954aSramat };
13070ab954aSramat 
13170ab954aSramat static char mdipathinfo_cb_str[] = "::print struct mdi_pathinfo";
13270ab954aSramat 
13370ab954aSramat const mdb_modinfo_t *
_mdb_init(void)13470ab954aSramat _mdb_init(void)
13570ab954aSramat {
13670ab954aSramat 	return (&modinfo);
13770ab954aSramat }
13870ab954aSramat 
13970ab954aSramat /*
14070ab954aSramat  * mdiclient()
14170ab954aSramat  *
14270ab954aSramat  * Dump mdi_client_t info and list all paths.
14370ab954aSramat  */
14470ab954aSramat /* ARGSUSED */
14570ab954aSramat static int
mdiclient(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)14670ab954aSramat mdiclient(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
14770ab954aSramat {
14870ab954aSramat 	struct mdi_client	value;
14970ab954aSramat 
15070ab954aSramat 	if (!(flags & DCMD_ADDRSPEC)) {
15170ab954aSramat 		mdb_warn("mdiclient: requires an address");
15270ab954aSramat 		return (DCMD_ERR);
15370ab954aSramat 	}
15470ab954aSramat 
15570ab954aSramat 	if (mdb_vread(&value, sizeof (struct mdi_client), addr)
15670ab954aSramat 	    != sizeof (struct mdi_client)) {
15770ab954aSramat 		mdb_warn("mdiclient: Failed read on %l#r\n", addr);
15870ab954aSramat 		return (DCMD_ERR);
15970ab954aSramat 	}
16070ab954aSramat 	mdb_printf("----------------- mdi_client @ %#lr ----------\n", addr);
16170ab954aSramat 	dump_string((uintptr_t)value.ct_guid, "GUID (ct_guid)");
16270ab954aSramat 	dump_string((uintptr_t)value.ct_drvname, "Driver Name (ct_drvname)");
16370ab954aSramat 	dump_state_str("Load Balance (ct_lb)", value.ct_lb, client_lb_str);
16470ab954aSramat 	mdb_printf("\n");
16570ab954aSramat 	mdb_printf("ct_hnext: %26l#r::print struct mdi_client\n",
16670ab954aSramat 	    value.ct_hnext);
16770ab954aSramat 	mdb_printf("ct_hprev: %26l#r::print struct mdi_client\n",
16870ab954aSramat 	    value.ct_hprev);
16970ab954aSramat 	mdb_printf("ct_dip: %28l#r::print struct dev_info\n", value.ct_dip);
17070ab954aSramat 	mdb_printf("ct_vhci: %27l#r::print struct mdi_vhci\n", value.ct_vhci);
17170ab954aSramat 	mdb_printf("ct_cprivate: %23l#r\n", value.ct_cprivate);
17270ab954aSramat 	mdb_printf("\nct_path_head: %22l#r::print struct mdi_pathinfo\n",
17370ab954aSramat 	    value.ct_path_head);
17470ab954aSramat 	mdb_printf("ct_path_tail: %22l#r::print struct mdi_pathinfo\n",
17570ab954aSramat 	    value.ct_path_tail);
17670ab954aSramat 	mdb_printf("ct_path_last: %22l#r::print struct mdi_pathfinfo\n",
17770ab954aSramat 	    value.ct_path_last);
17870ab954aSramat 	mdb_printf("ct_path_count: %21d\n", value.ct_path_count);
17970ab954aSramat 	mdb_printf("List of paths:\n");
18070ab954aSramat 	mdb_pwalk("mdipi_client_list", (mdb_walk_cb_t)mpxio_walk_cb,
18170ab954aSramat 	    mdipathinfo_cb_str, (uintptr_t)value.ct_path_head);
18270ab954aSramat 
18370ab954aSramat 	mdb_printf("\n");
18470ab954aSramat 	dump_state_str("Client State (ct_state)", value.ct_state,
18570ab954aSramat 	    mdi_client_states);
18670ab954aSramat 	dump_mutex(value.ct_mutex, "per-client mutex (ct_mutex):");
18770ab954aSramat 	mdb_printf("ct_flags: %26d\n", value.ct_flags);
18870ab954aSramat 	if (value.ct_flags) {
18970ab954aSramat 		dump_flags((unsigned long long)value.ct_flags, client_flags);
19070ab954aSramat 	}
19170ab954aSramat 	mdb_printf("ct_unstable: %23d\n", value.ct_unstable);
19270ab954aSramat 	dump_condvar(value.ct_unstable_cv, "ct_unstable_cv");
19370ab954aSramat 	dump_condvar(value.ct_failover_cv, "ct_failover_cv");
19470ab954aSramat 
19570ab954aSramat 	mdb_printf("\n");
196*3b442230SJordan Paige Hendricks 	mdb_printf("ct_failover_flags TEMP_VAR: %8d\n",
197*3b442230SJordan Paige Hendricks 	    value.ct_failover_flags);
198*3b442230SJordan Paige Hendricks 	mdb_printf("ct_failover_status UNUSED: %9d\n",
199*3b442230SJordan Paige Hendricks 	    value.ct_failover_status);
20070ab954aSramat 
20170ab954aSramat 	return (DCMD_OK);
20270ab954aSramat }
20370ab954aSramat 
20470ab954aSramat /*
20570ab954aSramat  * vhcilun()
20670ab954aSramat  *
20770ab954aSramat  * Get client info given a guid.
20870ab954aSramat  */
20970ab954aSramat /* ARGSUSED */
21070ab954aSramat static int
vhcilun(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)21170ab954aSramat vhcilun(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
21270ab954aSramat {
21370ab954aSramat 	if (!(flags & DCMD_ADDRSPEC)) {
21470ab954aSramat 		mdb_warn("sv_lun: requires an address");
21570ab954aSramat 		return (DCMD_ERR);
21670ab954aSramat 	}
21770ab954aSramat 
21870ab954aSramat 	return (i_vhcilun(addr, 0 /* display_single_guid */, 0));
21970ab954aSramat }
22070ab954aSramat 
22170ab954aSramat /*
22270ab954aSramat  * vhciguid()
22370ab954aSramat  *
22470ab954aSramat  * List all the clients.
22570ab954aSramat  */
22670ab954aSramat /* ARGSUSED */
22770ab954aSramat static int
vhciguid(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)22870ab954aSramat vhciguid(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
22970ab954aSramat {
23070ab954aSramat 
23170ab954aSramat 	struct i_ddi_soft_state ss;
23270ab954aSramat 	int i;
23370ab954aSramat 
23470ab954aSramat 	mdi_vhci_t	*mdi_vhci_value;
23570ab954aSramat 	mdi_client_t	*mdi_client_value;
23670ab954aSramat 	struct client_hash	*ct_hash_val;
23770ab954aSramat 	struct client_hash	*ct_hash_table_val;
23870ab954aSramat 
23970ab954aSramat 	int		len = strlen(MDI_HCI_CLASS_SCSI);
24070ab954aSramat 	int		mdi_vhci_len = sizeof (*mdi_vhci_value);
24170ab954aSramat 	int		mdi_client_len = sizeof (*mdi_client_value);
24270ab954aSramat 	int		ct_hash_len = sizeof (*ct_hash_val);
24370ab954aSramat 
24470ab954aSramat 	int		ct_hash_count = 0;
24570ab954aSramat 	char		*class;
24670ab954aSramat 	int		found = 0;
24770ab954aSramat 	uintptr_t	buf;
24870ab954aSramat 	uintptr_t	temp;
24970ab954aSramat 
25070ab954aSramat 
25170ab954aSramat 
25270ab954aSramat 	if (flags & DCMD_ADDRSPEC)
253*3b442230SJordan Paige Hendricks 		mdb_warn("This command doesn't use an address\n");
25470ab954aSramat 
25570ab954aSramat 	if (i_vhci_states(0, 0, 0, 0, &ss) != DCMD_OK)
25670ab954aSramat 		return (DCMD_ERR);
25770ab954aSramat 
25870ab954aSramat 	if (mdb_readvar(&buf, "mdi_vhci_head") == -1) {
25970ab954aSramat 		mdb_warn("mdi driver variable mdi_vhci_head not found.\n");
26070ab954aSramat 		mdb_warn("Is the driver loaded ?\n");
26170ab954aSramat 		return (DCMD_ERR);
26270ab954aSramat 	}
26370ab954aSramat 	mdb_printf("----------------- mdi_vhci_head @ %#lr ----------\n", buf);
26470ab954aSramat 	mdi_vhci_value = (mdi_vhci_t *)mdb_alloc(mdi_vhci_len, UM_SLEEP|UM_GC);
26570ab954aSramat 	if (mdb_vread(mdi_vhci_value, mdi_vhci_len, buf) != mdi_vhci_len) {
26670ab954aSramat 		mdb_warn("vhciguid: Failed read on %l#r\n", mdi_vhci_value);
26770ab954aSramat 		mdb_free(mdi_vhci_value, mdi_vhci_len);
26870ab954aSramat 		return (DCMD_ERR);
26970ab954aSramat 	}
27070ab954aSramat 	temp = (uintptr_t)mdi_vhci_value->vh_class;
27170ab954aSramat 	class = (char *)mdb_alloc(len, UM_SLEEP|UM_GC);
27270ab954aSramat 	if (mdb_vread(class, strlen(MDI_HCI_CLASS_SCSI), temp)
27370ab954aSramat 	    != strlen(MDI_HCI_CLASS_SCSI)) {
27470ab954aSramat 		mdb_warn("vhciguid: Failed read of class %l#r\n",
27570ab954aSramat 		    mdi_vhci_value);
27670ab954aSramat 		mdb_free(mdi_vhci_value, mdi_vhci_len);
27770ab954aSramat 		mdb_free(class, len);
27870ab954aSramat 		return (DCMD_ERR);
27970ab954aSramat 	}
28070ab954aSramat 	class[len] = 0;
28170ab954aSramat 	mdb_printf("----------------- class @ %s----------\n", class);
28270ab954aSramat 	while (class) {
28370ab954aSramat 		if (strcmp(class, MDI_HCI_CLASS_SCSI) == 0) {
28470ab954aSramat 			found = 1;
28570ab954aSramat 			break;
28670ab954aSramat 		}
28770ab954aSramat 		if (mdi_vhci_value->vh_next == NULL) {
28870ab954aSramat 			break;
28970ab954aSramat 		}
29070ab954aSramat 		temp = (uintptr_t)mdi_vhci_value->vh_next;
29170ab954aSramat 		if (mdb_vread(mdi_vhci_value, mdi_vhci_len, temp)
29270ab954aSramat 		    != mdi_vhci_len) {
29370ab954aSramat 			mdb_warn("vhciguid: Failed read on vh->next %l#r\n",
29470ab954aSramat 			    mdi_vhci_value);
29570ab954aSramat 			break;
29670ab954aSramat 		}
29770ab954aSramat 		temp = (uintptr_t)mdi_vhci_value->vh_class;
29870ab954aSramat 		if (mdb_vread(class, strlen(MDI_HCI_CLASS_SCSI), temp) !=
29970ab954aSramat 		    strlen(MDI_HCI_CLASS_SCSI)) {
30070ab954aSramat 			mdb_warn("vhciguid: Failed read on vh->next %l#r\n",
30170ab954aSramat 			    mdi_vhci_value);
30270ab954aSramat 			break;
30370ab954aSramat 		}
30470ab954aSramat 		class[len] = 0;
30570ab954aSramat 	}
30670ab954aSramat 
30770ab954aSramat 	if (found == 0) {
30870ab954aSramat 		mdb_warn("vhciguid: No scsi_vhci class found");
30970ab954aSramat 		mdb_free(mdi_vhci_value, mdi_vhci_len);
31070ab954aSramat 		mdb_free(class, len);
31170ab954aSramat 		return (DCMD_ERR);
31270ab954aSramat 	}
31370ab954aSramat 	mdb_printf("----- Number of devices found %d ----------\n",
31470ab954aSramat 	    mdi_vhci_value->vh_client_count);
31570ab954aSramat 	for (i = 0; i < CLIENT_HASH_TABLE_SIZE; i++) {
31670ab954aSramat 		ct_hash_table_val = &mdi_vhci_value->vh_client_table[i];
31770ab954aSramat 		if (ct_hash_table_val == NULL)
31870ab954aSramat 			continue;
31970ab954aSramat 
32070ab954aSramat 		/* Read client_hash structure */
32170ab954aSramat 		ct_hash_val = (struct client_hash *)mdb_alloc(ct_hash_len,
32270ab954aSramat 		    UM_SLEEP|UM_GC);
32370ab954aSramat 		temp = (uintptr_t)ct_hash_table_val;
32470ab954aSramat 		if (mdb_vread(ct_hash_val, ct_hash_len, temp) != ct_hash_len) {
32570ab954aSramat 			mdb_warn("Failed read on hash %l#r\n",
32670ab954aSramat 			    ct_hash_val);
32770ab954aSramat 			break;
32870ab954aSramat 		}
32970ab954aSramat 		mdb_printf("----hash[%d] %l#r: devices mapped  = %d --\n",
33070ab954aSramat 		    i, ct_hash_table_val, ct_hash_val->ct_hash_count);
33170ab954aSramat 		if (ct_hash_val->ct_hash_count == 0) {
33270ab954aSramat 			continue;
33370ab954aSramat 		}
33470ab954aSramat 
33570ab954aSramat 		ct_hash_count = ct_hash_val->ct_hash_count;
33670ab954aSramat 
33770ab954aSramat 		/* Read mdi_client structures */
33870ab954aSramat 		mdi_client_value = (mdi_client_t *)mdb_alloc(mdi_client_len,
33970ab954aSramat 		    UM_SLEEP|UM_GC);
34070ab954aSramat 		temp = (uintptr_t)ct_hash_val->ct_hash_head;
34170ab954aSramat 		if (mdb_vread(mdi_client_value, mdi_client_len, temp)
34270ab954aSramat 		    != mdi_client_len) {
34370ab954aSramat 			mdb_warn("Failed read on client %l#r\n",
34470ab954aSramat 			    mdi_client_value);
34570ab954aSramat 			break;
34670ab954aSramat 		}
34770ab954aSramat 		mdb_printf("mdi_client %l#r %l#r ------\n",
34870ab954aSramat 		    mdi_client_value, mdi_client_value->ct_vprivate);
34970ab954aSramat 		vhcilun((uintptr_t)mdi_client_value->ct_vprivate,
35070ab954aSramat 		    DCMD_ADDRSPEC, 0, 0);
35170ab954aSramat 
35270ab954aSramat 		while (--ct_hash_count) {
35370ab954aSramat 			temp = (uintptr_t)mdi_client_value->ct_hnext;
35470ab954aSramat 			if (mdb_vread(mdi_client_value, mdi_client_len,
35570ab954aSramat 			    temp) != mdi_client_len) {
35670ab954aSramat 				mdb_warn("Failed read on client %l#r\n",
35770ab954aSramat 				    mdi_client_value);
35870ab954aSramat 				break;
35970ab954aSramat 			}
36070ab954aSramat 			vhcilun((uintptr_t)mdi_client_value->ct_vprivate,
36170ab954aSramat 			    DCMD_ADDRSPEC, 0, 0);
36270ab954aSramat 		}
36370ab954aSramat 	}
36470ab954aSramat 	mdb_printf("----------done----------\n");
36570ab954aSramat 
36670ab954aSramat 	return (DCMD_OK);
36770ab954aSramat }
36870ab954aSramat 
36970ab954aSramat /*
37070ab954aSramat  * Print the flag name by comparing flags to the mask variable.
37170ab954aSramat  */
37270ab954aSramat static void
dump_flags(unsigned long long flags,char ** strings)37370ab954aSramat dump_flags(unsigned long long flags, char **strings)
37470ab954aSramat {
37570ab954aSramat 	int i, linel = 8, first = 1;
37670ab954aSramat 	unsigned long long mask = 1;
37770ab954aSramat 
37870ab954aSramat 	for (i = 0; i < 64; i++) {
37970ab954aSramat 		if (strings[i] == NULL)
38070ab954aSramat 			break;
38170ab954aSramat 		if (flags & mask) {
38270ab954aSramat 			if (!first) {
38370ab954aSramat 				mdb_printf(" | ");
38470ab954aSramat 			} else {
38570ab954aSramat 				first = 0;
38670ab954aSramat 			}
38770ab954aSramat 			/* make output pretty */
38870ab954aSramat 			linel += strlen(strings[i]) + 3;
38970ab954aSramat 			if (linel > 80) {
39070ab954aSramat 				mdb_printf("\n\t");
39170ab954aSramat 				linel = strlen(strings[i]) + 1 + 8;
39270ab954aSramat 			}
39370ab954aSramat 			mdb_printf("%s", strings[i]);
39470ab954aSramat 		}
39570ab954aSramat 		mask <<= 1;
39670ab954aSramat 	}
39770ab954aSramat 	mdb_printf("\n");
39870ab954aSramat }
39970ab954aSramat 
40070ab954aSramat /* ARGSUSED */
40170ab954aSramat static int
vhci_states(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)40270ab954aSramat vhci_states(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
40370ab954aSramat {
40470ab954aSramat 	return (i_vhci_states(addr, flags, argc, argv, NULL));
40570ab954aSramat }
40670ab954aSramat 
40770ab954aSramat /*
40870ab954aSramat  * dump_states()
40970ab954aSramat  *
41070ab954aSramat  * Print the state information for vhci_states().
41170ab954aSramat  */
41270ab954aSramat static int
dump_states(uintptr_t array_vaddr,int verbose,struct i_ddi_soft_state * sp)41370ab954aSramat dump_states(uintptr_t array_vaddr, int verbose, struct i_ddi_soft_state *sp)
41470ab954aSramat {
41570ab954aSramat 	int i;
41670ab954aSramat 	int array_size;
41770ab954aSramat 	struct i_ddi_soft_state *ss;
41870ab954aSramat 	struct scsi_vhci vhci;
41970ab954aSramat 
42070ab954aSramat 	if (sp == NULL) {
42170ab954aSramat 		ss = (struct i_ddi_soft_state *)mdb_alloc(sizeof (*ss),
42270ab954aSramat 		    UM_SLEEP|UM_GC);
42370ab954aSramat 	} else {
42470ab954aSramat 		ss = sp;
42570ab954aSramat 	}
42670ab954aSramat 	if (mdb_vread(ss, sizeof (*ss), array_vaddr) != sizeof (*ss)) {
42770ab954aSramat 		mdb_warn("Cannot read softstate struct (Invalid pointer?).\n");
42870ab954aSramat 		return (DCMD_ERR);
42970ab954aSramat 	}
43070ab954aSramat 	array_size = ss->n_items * (sizeof (void *));
43170ab954aSramat 	array_vaddr = (uintptr_t)ss->array;
43270ab954aSramat 	ss->array = mdb_alloc(array_size, UM_SLEEP|UM_GC);
43370ab954aSramat 	if (mdb_vread(ss->array, array_size, array_vaddr) != array_size) {
43470ab954aSramat 		mdb_warn("Corrupted softstate struct.\n");
43570ab954aSramat 		return (DCMD_ERR);
43670ab954aSramat 	}
43770ab954aSramat 	if (sp != NULL)
43870ab954aSramat 		return (DCMD_OK);
43970ab954aSramat 	if (verbose) {
44070ab954aSramat 	/*
44170ab954aSramat 	 * ss->size is of type size_t which is 4 bytes and 8 bytes
44270ab954aSramat 	 * on 32-bit and 64-bit systems respectively.
44370ab954aSramat 	 */
44470ab954aSramat #ifdef _LP64
44570ab954aSramat 		mdb_printf("Softstate size is %lld(0x%llx) bytes.\n\n",
44670ab954aSramat 		    ss->size, ss->size);
44770ab954aSramat #else
44870ab954aSramat 		mdb_printf("Softstate size is %ld(0x%lx) bytes.\n\n",
44970ab954aSramat 		    ss->size, ss->size);
45070ab954aSramat #endif
45170ab954aSramat 		mdb_printf("state pointer\t\t\t\t\tinstance\n");
45270ab954aSramat 		mdb_printf("=============\t\t\t\t\t========\n");
45370ab954aSramat 	}
45470ab954aSramat 	for (i = 0; i < ss->n_items; i++) {
45570ab954aSramat 		if (ss->array[i] == 0)
45670ab954aSramat 			continue;
45770ab954aSramat 
45870ab954aSramat 		if (mdb_vread(&vhci, sizeof (vhci), (uintptr_t)ss->array[i])
45970ab954aSramat 		    != sizeof (vhci)) {
46070ab954aSramat 			mdb_warn("Corrupted softstate struct.\n");
46170ab954aSramat 			return (DCMD_ERR);
46270ab954aSramat 		}
46370ab954aSramat 		if (verbose) {
46470ab954aSramat 			mdb_printf("%l#r::print struct scsi_vhci\t\t   %d\n",
46570ab954aSramat 			    ss->array[i], i);
46670ab954aSramat 			mdb_printf("\nvhci_conf_flags: %d\n",
46770ab954aSramat 			    vhci.vhci_conf_flags);
46870ab954aSramat 			if (vhci.vhci_conf_flags) {
46970ab954aSramat 				mdb_printf("\t");
47070ab954aSramat 				dump_flags((unsigned long long)
47170ab954aSramat 				    vhci.vhci_conf_flags, vhci_conf_flags);
47270ab954aSramat 			}
47370ab954aSramat 		} else {
47470ab954aSramat 			mdb_printf("%l#r\n", ss->array[i]);
47570ab954aSramat 		}
47670ab954aSramat 	}
47770ab954aSramat 	return (DCMD_OK);
47870ab954aSramat }
47970ab954aSramat 
48070ab954aSramat static int
get_mdbstr(uintptr_t addr,char * string_val)48170ab954aSramat get_mdbstr(uintptr_t addr, char *string_val)
48270ab954aSramat {
48370ab954aSramat 	if (mdb_readstr(string_val, MAXNAMELEN, addr) == -1) {
48470ab954aSramat 		mdb_warn("Error Reading String from %l#r\n", addr);
48570ab954aSramat 		return (1);
48670ab954aSramat 	}
48770ab954aSramat 
48870ab954aSramat 	return (0);
48970ab954aSramat }
49070ab954aSramat 
49170ab954aSramat static void
dump_state_str(char * name,uintptr_t addr,char ** strings)49270ab954aSramat dump_state_str(char *name, uintptr_t addr, char **strings)
49370ab954aSramat {
49470ab954aSramat 	mdb_printf("%s: %s (%l#r)\n", name, strings[(unsigned long)addr], addr);
49570ab954aSramat }
49670ab954aSramat 
49770ab954aSramat /* VHCI UTILS */
49870ab954aSramat 
49970ab954aSramat /*
50070ab954aSramat  * i_vhci_states()
50170ab954aSramat  *
50270ab954aSramat  * Internal routine for vhci_states() to check for -v arg and then
50370ab954aSramat  * print state info.
50470ab954aSramat  */
50570ab954aSramat /* ARGSUSED */
50670ab954aSramat static int
i_vhci_states(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv,struct i_ddi_soft_state * sp)50770ab954aSramat i_vhci_states(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv,
50870ab954aSramat     struct i_ddi_soft_state *sp)
50970ab954aSramat {
51070ab954aSramat 	uintptr_t adr;
51170ab954aSramat 	int verbose = 0;
51270ab954aSramat 
51370ab954aSramat 	if (mdb_readvar(&adr, "vhci_softstate") == -1) {
51470ab954aSramat 		mdb_warn("vhci driver variable vhci_softstate not found.\n");
51570ab954aSramat 		mdb_warn("Is the driver loaded ?\n");
51670ab954aSramat 		return (DCMD_ERR);
51770ab954aSramat 	}
51870ab954aSramat 	if (sp == NULL) {
51970ab954aSramat 		if (mdb_getopts(argc, argv,
520*3b442230SJordan Paige Hendricks 		    'v', MDB_OPT_SETBITS, TRUE, &verbose, NULL) != argc) {
52170ab954aSramat 			return (DCMD_USAGE);
52270ab954aSramat 		}
52370ab954aSramat 	}
52470ab954aSramat 
52570ab954aSramat 	return (dump_states(adr, verbose, sp));
52670ab954aSramat }
52770ab954aSramat 
52870ab954aSramat /*
52970ab954aSramat  * i_vhcilun()
53070ab954aSramat  *
53170ab954aSramat  * Internal routine for vhciguid() to print client info.
53270ab954aSramat  */
53370ab954aSramat static int
i_vhcilun(uintptr_t addr,uint_t display_single_guid,char * guid)53470ab954aSramat i_vhcilun(uintptr_t addr, uint_t display_single_guid, char *guid)
53570ab954aSramat {
53670ab954aSramat 
53770ab954aSramat 	scsi_vhci_lun_t		value;
53870ab954aSramat 	struct dev_info		dev_info_value;
53970ab954aSramat 	char			string_val[MAXNAMELEN];
54070ab954aSramat 	int			found = 0;
54170ab954aSramat 	struct mdi_client	ct_value;
54270ab954aSramat 	uintptr_t		temp_addr;
54370ab954aSramat 
54470ab954aSramat 	do {
54570ab954aSramat 		if (mdb_vread(&value, sizeof (scsi_vhci_lun_t), addr) !=
54670ab954aSramat 		    sizeof (scsi_vhci_lun_t)) {
54770ab954aSramat 			mdb_warn("sv_lun: Failed read on %l#r", addr);
54870ab954aSramat 			return (DCMD_ERR);
54970ab954aSramat 		}
55070ab954aSramat 
55170ab954aSramat 		temp_addr = addr;
55270ab954aSramat 		addr = (uintptr_t)value.svl_hash_next;
55370ab954aSramat 
55470ab954aSramat 		if (!get_mdbstr((uintptr_t)value.svl_lun_wwn, string_val)) {
55570ab954aSramat 			if (display_single_guid) {
55670ab954aSramat 				if (strcmp(string_val, guid) == 0) {
55770ab954aSramat 					found = 1;
55870ab954aSramat 				} else continue;
55970ab954aSramat 			}
56070ab954aSramat 		}
56170ab954aSramat 
56270ab954aSramat 		mdb_printf("%t%l#r::print struct scsi_vhci_lun", temp_addr);
56370ab954aSramat 
56470ab954aSramat 		if (mdb_vread(&dev_info_value, sizeof (struct dev_info),
56570ab954aSramat 		    (uintptr_t)value.svl_dip) != sizeof (struct dev_info)) {
56670ab954aSramat 			mdb_warn("svl_dip: Failed read on %l#r",
56770ab954aSramat 			    value.svl_dip);
56870ab954aSramat 			return (DCMD_ERR);
56970ab954aSramat 		}
57070ab954aSramat 
57170ab954aSramat 		mdb_printf("\n%tGUID: %s\n", string_val);
57270ab954aSramat 		if (value.svl_active_pclass != NULL) {
57370ab954aSramat 			if (!get_mdbstr((uintptr_t)value.svl_active_pclass,
57470ab954aSramat 			    string_val)) {
57570ab954aSramat 				mdb_printf("%tActv_cl: %s", string_val);
57670ab954aSramat 			}
57770ab954aSramat 		} else {
57870ab954aSramat 			mdb_printf("   No active pclass");
57970ab954aSramat 		}
58070ab954aSramat 		if (display_single_guid) {
58170ab954aSramat 			mdb_printf(" (%l#r)", value.svl_active_pclass);
58270ab954aSramat 		}
58370ab954aSramat 
58470ab954aSramat 		mdb_printf("\n%t%l#r::print struct mdi_client",
58570ab954aSramat 		    dev_info_value.devi_mdi_client);
58670ab954aSramat 
58770ab954aSramat 		if (value.svl_flags) {
58870ab954aSramat 			mdb_printf("\t");
58970ab954aSramat 			dump_flags((unsigned long long)value.svl_flags,
59070ab954aSramat 			    svlun_flags);
59170ab954aSramat 		} else {
59270ab954aSramat 			mdb_printf("\n");
59370ab954aSramat 		}
59470ab954aSramat 
59570ab954aSramat 		if (found) {
59670ab954aSramat 			mdiclient((uintptr_t)dev_info_value.devi_mdi_client,
59770ab954aSramat 			    DCMD_ADDRSPEC, 0, 0);
59870ab954aSramat 		} else {
59970ab954aSramat 			if (mdb_vread(&ct_value, sizeof (struct mdi_client),
60070ab954aSramat 			    (uintptr_t)dev_info_value.devi_mdi_client) !=
60170ab954aSramat 			    sizeof (struct mdi_client)) {
60270ab954aSramat 				mdb_warn("mdiclient: Failed read on %l#r",
60370ab954aSramat 				    dev_info_value.devi_mdi_client);
60470ab954aSramat 				return (DCMD_ERR);
60570ab954aSramat 			}
60670ab954aSramat 			if (ct_value.ct_flags) {
60770ab954aSramat 				mdb_printf("\t");
60870ab954aSramat 				dump_flags((unsigned long long)
60970ab954aSramat 				    ct_value.ct_flags, client_flags);
61070ab954aSramat 			}
61170ab954aSramat 			mdb_printf("%t");
61270ab954aSramat 			dump_state_str("LB", ct_value.ct_lb, client_lb_str);
61370ab954aSramat 			mdb_printf("\n");
61470ab954aSramat 		}
61570ab954aSramat 	} while (addr && !found);
61670ab954aSramat 	return (DCMD_OK);
61770ab954aSramat }
61870ab954aSramat 
61970ab954aSramat static void
dump_mutex(kmutex_t m,char * name)62070ab954aSramat dump_mutex(kmutex_t m, char *name)
62170ab954aSramat {
62270ab954aSramat 	mdb_printf("%s is%s held\n", name, FT(m, uint64_t) == 0 ? " not" : "");
62370ab954aSramat }
62470ab954aSramat 
62570ab954aSramat static void
dump_condvar(kcondvar_t c,char * name)62670ab954aSramat dump_condvar(kcondvar_t c, char *name)
62770ab954aSramat {
62870ab954aSramat 	mdb_printf("Threads sleeping on %s = %d\n", name, (int)FT(c, ushort_t));
62970ab954aSramat }
63070ab954aSramat 
63170ab954aSramat static void
dump_string(uintptr_t addr,char * name)63270ab954aSramat dump_string(uintptr_t addr, char *name)
63370ab954aSramat {
63470ab954aSramat 	char string_val[MAXNAMELEN];
63570ab954aSramat 
63670ab954aSramat 	if (get_mdbstr(addr, string_val)) {
63770ab954aSramat 		return;
63870ab954aSramat 	}
63970ab954aSramat 	mdb_printf("%s: %s (%l#r)\n", name, string_val, addr);
64070ab954aSramat }
64170ab954aSramat 
64270ab954aSramat /* ARGSUSED */
64370ab954aSramat static int
mpxio_walk_cb(uintptr_t addr,const void * data,void * cbdata)64470ab954aSramat mpxio_walk_cb(uintptr_t addr, const void *data, void *cbdata)
64570ab954aSramat {
64670ab954aSramat 	mdb_printf("%t%l#r%s\n", addr, (char *)cbdata);
64770ab954aSramat 	return (0);
64870ab954aSramat }
649