xref: /titanic_53/usr/src/cmd/mdb/common/modules/genunix/damap.c (revision 5d562cec9a5c49bc665980c775f32f708cb2f3e9)
14c06356bSdh142964 /*
24c06356bSdh142964  * CDDL HEADER START
34c06356bSdh142964  *
44c06356bSdh142964  * The contents of this file are subject to the terms of the
54c06356bSdh142964  * Common Development and Distribution License (the "License").
64c06356bSdh142964  * You may not use this file except in compliance with the License.
74c06356bSdh142964  *
84c06356bSdh142964  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
94c06356bSdh142964  * or http://www.opensolaris.org/os/licensing.
104c06356bSdh142964  * See the License for the specific language governing permissions
114c06356bSdh142964  * and limitations under the License.
124c06356bSdh142964  *
134c06356bSdh142964  * When distributing Covered Code, include this CDDL HEADER in each
144c06356bSdh142964  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
154c06356bSdh142964  * If applicable, add the following below this CDDL HEADER, with the
164c06356bSdh142964  * fields enclosed by brackets "[]" replaced with your own identifying
174c06356bSdh142964  * information: Portions Copyright [yyyy] [name of copyright owner]
184c06356bSdh142964  *
194c06356bSdh142964  * CDDL HEADER END
204c06356bSdh142964  */
214c06356bSdh142964 /*
22*5d562cecSMilos Muzik  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
234c06356bSdh142964  */
244c06356bSdh142964 
254c06356bSdh142964 #include <mdb/mdb_modapi.h>
264c06356bSdh142964 #include <sys/sysmacros.h>
274c06356bSdh142964 #include <sys/sunddi.h>
28d189c170SReed #include <sys/damap.h>
294c06356bSdh142964 #include <sys/damap_impl.h>
304c06356bSdh142964 
314c06356bSdh142964 #include "damap.h"
324c06356bSdh142964 
334c06356bSdh142964 void
damap_help(void)344c06356bSdh142964 damap_help(void)
354c06356bSdh142964 {
364c06356bSdh142964 	mdb_printf("Print the damap at the address given.\n");
374c06356bSdh142964 	mdb_printf("\n");
384c06356bSdh142964 	mdb_printf("EXAMPLE: SCSI: To display the SCSI tgtmap damaps ");
394c06356bSdh142964 	mdb_printf("associated with a scsi HBA driver iport dip:\n");
404c06356bSdh142964 	mdb_printf("\n");
414c06356bSdh142964 	mdb_printf("::devbindings -q <driver_name>\n");
424c06356bSdh142964 	mdb_printf("\n");
434c06356bSdh142964 	mdb_printf("<iport-dip>::print struct dev_info devi_driver_data|");
444c06356bSdh142964 	mdb_printf("::print scsi_hba_tran_t tran_tgtmap|");
454c06356bSdh142964 	mdb_printf("::print impl_scsi_tgtmap_t ");
464c06356bSdh142964 	mdb_printf("tgtmap_dam[0] tgtmap_dam[1]|::damap\n");
474c06356bSdh142964 }
484c06356bSdh142964 
494c06356bSdh142964 static char *
local_strdup(const char * s)504c06356bSdh142964 local_strdup(const char *s)
514c06356bSdh142964 {
524c06356bSdh142964 	if (s)
534c06356bSdh142964 		return (strcpy(mdb_alloc(strlen(s) + 1, UM_SLEEP), s));
544c06356bSdh142964 	else
554c06356bSdh142964 		return (NULL);
564c06356bSdh142964 }
574c06356bSdh142964 
584c06356bSdh142964 static void
local_strfree(const char * s)594c06356bSdh142964 local_strfree(const char *s)
604c06356bSdh142964 {
614c06356bSdh142964 	if (s)
624c06356bSdh142964 		mdb_free((void *)s, strlen(s) + 1);
634c06356bSdh142964 }
644c06356bSdh142964 
654c06356bSdh142964 static void
bitset_free(bitset_t * bs,int embedded)664c06356bSdh142964 bitset_free(bitset_t *bs, int embedded)
674c06356bSdh142964 {
684c06356bSdh142964 	if (bs == NULL)
694c06356bSdh142964 		return;
704c06356bSdh142964 	if (bs->bs_set && bs->bs_words)
714c06356bSdh142964 		mdb_free(bs->bs_set, bs->bs_words * sizeof (ulong_t));
724c06356bSdh142964 	if (!embedded)
734c06356bSdh142964 		mdb_free(bs, sizeof (*bs));	/* not embedded, free */
744c06356bSdh142964 }
754c06356bSdh142964 
764c06356bSdh142964 static bitset_t *
bitset_get(uintptr_t bsaddr)774c06356bSdh142964 bitset_get(uintptr_t bsaddr)
784c06356bSdh142964 {
794c06356bSdh142964 	bitset_t	*bs;
804c06356bSdh142964 
814c06356bSdh142964 	bs = mdb_zalloc(sizeof (*bs), UM_SLEEP);
824c06356bSdh142964 	if (mdb_vread(bs, sizeof (*bs), bsaddr) == -1) {
834c06356bSdh142964 		mdb_warn("couldn't read bitset 0x%p", bsaddr);
844c06356bSdh142964 		bitset_free(bs, 0);
854c06356bSdh142964 		return (NULL);
864c06356bSdh142964 	}
874c06356bSdh142964 
884c06356bSdh142964 	bsaddr = (uintptr_t)bs->bs_set;
894c06356bSdh142964 	bs->bs_set = mdb_alloc(bs->bs_words * sizeof (ulong_t), UM_SLEEP);
904c06356bSdh142964 	if (mdb_vread(bs->bs_set,
914c06356bSdh142964 	    bs->bs_words * sizeof (ulong_t), bsaddr) == -1) {
924c06356bSdh142964 		mdb_warn("couldn't read bitset bs_set 0x%p", bsaddr);
934c06356bSdh142964 		bitset_free(bs, 0);
944c06356bSdh142964 		return (NULL);
954c06356bSdh142964 	}
964c06356bSdh142964 	return (bs);
974c06356bSdh142964 
984c06356bSdh142964 }
994c06356bSdh142964 
1004c06356bSdh142964 static void
damap_free(struct dam * dam,void ** kdamda,int kdamda_n)1014c06356bSdh142964 damap_free(struct dam *dam, void **kdamda, int kdamda_n)
1024c06356bSdh142964 {
1034c06356bSdh142964 	int			i;
1044c06356bSdh142964 	struct i_ddi_soft_state *ss;
1054c06356bSdh142964 	dam_da_t		*da;
1064c06356bSdh142964 
1074c06356bSdh142964 	if (dam) {
1084c06356bSdh142964 		/* free in dam_da_t softstate */
1094c06356bSdh142964 		ss = (struct i_ddi_soft_state *)dam->dam_da;
1104c06356bSdh142964 		if (ss) {
1114c06356bSdh142964 			if (ss->n_items && ss->array) {
1124c06356bSdh142964 				for (i = 0; i < ss->n_items; i++) {
1134c06356bSdh142964 					da = ss->array[i];
1144c06356bSdh142964 					if (da == NULL)
1154c06356bSdh142964 						continue;
1164c06356bSdh142964 					local_strfree(da->da_addr);
1174c06356bSdh142964 					mdb_free(da, sizeof (*da));
1184c06356bSdh142964 				}
1194c06356bSdh142964 			}
1204c06356bSdh142964 
1214c06356bSdh142964 			mdb_free(ss, sizeof (*ss));
1224c06356bSdh142964 		}
1234c06356bSdh142964 
1244c06356bSdh142964 		/* free dam_active/stable/report_set embedded in dam */
1254c06356bSdh142964 		bitset_free(&dam->dam_report_set, 1);
1264c06356bSdh142964 		bitset_free(&dam->dam_stable_set, 1);
1274c06356bSdh142964 		bitset_free(&dam->dam_active_set, 1);
1284c06356bSdh142964 
1294c06356bSdh142964 		/* free dam_name */
1304c06356bSdh142964 		local_strfree(dam->dam_name);
1314c06356bSdh142964 
1324c06356bSdh142964 		/* free dam */
1334c06356bSdh142964 		mdb_free(dam, sizeof (*dam));
1344c06356bSdh142964 	}
1354c06356bSdh142964 
1364c06356bSdh142964 	if (kdamda)
1374c06356bSdh142964 		mdb_free(kdamda, kdamda_n * sizeof (void *));
1384c06356bSdh142964 }
1394c06356bSdh142964 
1404c06356bSdh142964 /*
1414c06356bSdh142964  * The dam implementation uses a number of different abstractions. Given a
1424c06356bSdh142964  * pointer to a damap_t, this function make an mdb instantiation of the dam -
1434c06356bSdh142964  * many, but not all, of the different abstractions used in the dam
1444c06356bSdh142964  * implementation are also instantiated in mdb. This means that callers of
1454c06356bSdh142964  * damap_get can perform some (but not all) types of structure pointer
1464c06356bSdh142964  * traversals.
1474c06356bSdh142964  */
1484c06356bSdh142964 struct dam *
damap_get(uintptr_t damaddr,void *** pkdamda,int * pkdamda_n)1494c06356bSdh142964 damap_get(uintptr_t damaddr, void ***pkdamda, int *pkdamda_n)
1504c06356bSdh142964 {
1514c06356bSdh142964 	/* variables that hold instantiation read from kernel */
1524c06356bSdh142964 	struct dam		kdam;
1534c06356bSdh142964 	char			kstring[MAXPATHLEN];
1544c06356bSdh142964 	struct i_ddi_soft_state kss;
1554c06356bSdh142964 	void			**kssarray = NULL;
1564c06356bSdh142964 	int			array_sz = 0;
1574c06356bSdh142964 
1584c06356bSdh142964 	/* variables that hold mdb instantiation */
1594c06356bSdh142964 	struct dam		*dam = NULL;
1604c06356bSdh142964 	struct i_ddi_soft_state *ss;
1614c06356bSdh142964 	bitset_t		*bs;
1624c06356bSdh142964 	dam_da_t		*da;
1634c06356bSdh142964 
1644c06356bSdh142964 	int			i;
1654c06356bSdh142964 
1664c06356bSdh142964 	/* read kernel: dam */
1674c06356bSdh142964 	if (mdb_vread(&kdam, sizeof (kdam), damaddr) == -1) {
1684c06356bSdh142964 		mdb_warn("couldn't read dam 0x%p", damaddr);
1694c06356bSdh142964 		goto err;
1704c06356bSdh142964 	}
1714c06356bSdh142964 
1724c06356bSdh142964 	/* read kernel: dam->dam_name */
1734c06356bSdh142964 	mdb_readstr(kstring, sizeof (kstring), (uintptr_t)kdam.dam_name);
1744c06356bSdh142964 
1754c06356bSdh142964 	/* read kernel: dam->dam_da (softstate) */
1764c06356bSdh142964 	if (mdb_vread(&kss, sizeof (kss), (uintptr_t)kdam.dam_da) == -1) {
1774c06356bSdh142964 		mdb_warn("couldn't read dam dam_da 0x%p",
1784c06356bSdh142964 		    (uintptr_t)kdam.dam_da);
1794c06356bSdh142964 		goto err;
1804c06356bSdh142964 	}
1814c06356bSdh142964 
1824c06356bSdh142964 	/* read kernel ((struct i_ddi_soft_state *)dam->dam_da)->array */
1834c06356bSdh142964 	array_sz = kss.n_items * sizeof (void *);
1844c06356bSdh142964 	kssarray = mdb_alloc(array_sz, UM_SLEEP);
1854c06356bSdh142964 	if (mdb_vread(kssarray, array_sz, (uintptr_t)kss.array) == -1) {
1864c06356bSdh142964 		mdb_warn("couldn't read dam dam_da array 0x%p",
1874c06356bSdh142964 		    (uintptr_t)kss.array);
1884c06356bSdh142964 		goto err;
1894c06356bSdh142964 	}
1904c06356bSdh142964 
1914c06356bSdh142964 	/*
1924c06356bSdh142964 	 * Produce mdb instantiation of kernel data structures.
1934c06356bSdh142964 	 *
1944c06356bSdh142964 	 * Structure copy kdam to dam, then clear out pointers in dam (some
1954c06356bSdh142964 	 * will be filled in by mdb instantiation code below).
1964c06356bSdh142964 	 */
1974c06356bSdh142964 	dam = mdb_zalloc(sizeof (*dam), UM_SLEEP);
1984c06356bSdh142964 	*dam = kdam;
1994c06356bSdh142964 	dam->dam_name = NULL;
2004c06356bSdh142964 
2014c06356bSdh142964 	dam->dam_active_set.bs_set = NULL;
2024c06356bSdh142964 	dam->dam_stable_set.bs_set = NULL;
2034c06356bSdh142964 	dam->dam_report_set.bs_set = NULL;
2044c06356bSdh142964 
2054c06356bSdh142964 	dam->dam_da = NULL;
2064c06356bSdh142964 	/* dam_addr_hash, dam_taskqp, dam_kstatp left as kernel addresses */
2074c06356bSdh142964 
2084c06356bSdh142964 	/* fill in dam_name */
2094c06356bSdh142964 	dam->dam_name = local_strdup(kstring);
2104c06356bSdh142964 
2114c06356bSdh142964 	/* fill in dam_active/stable/report_set embedded in the dam */
2124c06356bSdh142964 	bs = bitset_get(damaddr + (offsetof(struct dam, dam_active_set)));
2134c06356bSdh142964 	if (bs) {
2144c06356bSdh142964 		dam->dam_active_set = *bs;
2154c06356bSdh142964 		mdb_free(bs, sizeof (*bs));
2164c06356bSdh142964 	}
2174c06356bSdh142964 	bs = bitset_get(damaddr + (offsetof(struct dam, dam_stable_set)));
2184c06356bSdh142964 	if (bs) {
2194c06356bSdh142964 		dam->dam_stable_set = *bs;
2204c06356bSdh142964 		mdb_free(bs, sizeof (*bs));
2214c06356bSdh142964 	}
2224c06356bSdh142964 	bs = bitset_get(damaddr + (offsetof(struct dam, dam_report_set)));
2234c06356bSdh142964 	if (bs) {
2244c06356bSdh142964 		dam->dam_report_set = *bs;
2254c06356bSdh142964 		mdb_free(bs, sizeof (*bs));
2264c06356bSdh142964 	}
2274c06356bSdh142964 
2284c06356bSdh142964 	/* fill in dam_da_t softstate */
2294c06356bSdh142964 	ss = mdb_zalloc(sizeof (struct i_ddi_soft_state), UM_SLEEP);
2304c06356bSdh142964 	*ss = kss;
2314c06356bSdh142964 	ss->next = NULL;
2324c06356bSdh142964 	ss->array = mdb_zalloc(array_sz, UM_SLEEP);
2334c06356bSdh142964 	dam->dam_da = ss;
2344c06356bSdh142964 	for (i = 0; i < kss.n_items; i++) {
2354c06356bSdh142964 		if (kssarray[i] == NULL)
2364c06356bSdh142964 			continue;
2374c06356bSdh142964 		da = ss->array[i] = mdb_zalloc(sizeof (*da), UM_SLEEP);
2384c06356bSdh142964 		if (mdb_vread(da, sizeof (*da), (uintptr_t)kssarray[i]) == -1) {
2394c06356bSdh142964 			mdb_warn("couldn't read dam dam_da %d 0x%p", i,
2404c06356bSdh142964 			    (uintptr_t)kss.array);
2414c06356bSdh142964 			goto err;
2424c06356bSdh142964 		}
2434c06356bSdh142964 		/* da_nvl, da_ppriv_rpt, da_nvl_rpt left as kernel addresses */
2444c06356bSdh142964 
2454c06356bSdh142964 		/* read kernel: da->da_addr */
2464c06356bSdh142964 		mdb_readstr(kstring, sizeof (kstring), (uintptr_t)da->da_addr);
2474c06356bSdh142964 		da->da_addr = local_strdup(kstring);
2484c06356bSdh142964 	}
2494c06356bSdh142964 
2504c06356bSdh142964 	/* return array of kernel dam_da_t pointers associated with each id */
2514c06356bSdh142964 	*pkdamda = kssarray;
2524c06356bSdh142964 	*pkdamda_n = array_sz / sizeof (void *);
2534c06356bSdh142964 
2544c06356bSdh142964 	/* return pointer to mdb instantiation of the dam */
2554c06356bSdh142964 	return (dam);
2564c06356bSdh142964 
2574c06356bSdh142964 err:	damap_free(dam, kssarray, array_sz / sizeof (void *));
2584c06356bSdh142964 	*pkdamda = NULL;
2594c06356bSdh142964 	*pkdamda_n = 0;
2604c06356bSdh142964 	return (NULL);
2614c06356bSdh142964 }
2624c06356bSdh142964 
2634c06356bSdh142964 /*ARGSUSED*/
2644c06356bSdh142964 static void
damap_print(struct dam * dam,void ** kdamda,int kdamda_n)2654c06356bSdh142964 damap_print(struct dam *dam, void **kdamda, int kdamda_n)
2664c06356bSdh142964 {
2674c06356bSdh142964 	struct i_ddi_soft_state	*ss;
2684c06356bSdh142964 	dam_da_t		*da;
2694c06356bSdh142964 	int			i;
2704c06356bSdh142964 
2714c06356bSdh142964 	mdb_printf("%s:\n", dam->dam_name);
2724c06356bSdh142964 
2734c06356bSdh142964 	ss = (struct i_ddi_soft_state *)dam->dam_da;
2744c06356bSdh142964 	if (ss == NULL)
2754c06356bSdh142964 		return;
2764c06356bSdh142964 
2774c06356bSdh142964 	if ((ss->n_items == 0) || (ss->array == NULL))
2784c06356bSdh142964 		return;
2794c06356bSdh142964 
280*5d562cecSMilos Muzik 	mdb_printf("    #: %-20s [ASR] ref config-private   provider-private\n",
281*5d562cecSMilos Muzik 	    "address");
2824c06356bSdh142964 	for (i = 0; i < ss->n_items; i++) {
2834c06356bSdh142964 		da = ss->array[i];
2844c06356bSdh142964 		if (da == NULL)
2854c06356bSdh142964 			continue;
2864c06356bSdh142964 
2874c06356bSdh142964 		/* Print index and address. */
288*5d562cecSMilos Muzik 		mdb_printf("  %3d: %-20s [", i, da->da_addr);
2894c06356bSdh142964 
2904c06356bSdh142964 		/* Print shorthand of Active/Stable/Report set membership */
2914c06356bSdh142964 		if (BT_TEST(dam->dam_active_set.bs_set, i))
2924c06356bSdh142964 			mdb_printf("A");
2934c06356bSdh142964 		else
2944c06356bSdh142964 			mdb_printf(".");
2954c06356bSdh142964 		if (BT_TEST(dam->dam_stable_set.bs_set, i))
2964c06356bSdh142964 			mdb_printf("S");
2974c06356bSdh142964 		else
2984c06356bSdh142964 			mdb_printf(".");
2994c06356bSdh142964 		if (BT_TEST(dam->dam_report_set.bs_set, i))
3004c06356bSdh142964 			mdb_printf("R");
3014c06356bSdh142964 		else
3024c06356bSdh142964 			mdb_printf(".");
3034c06356bSdh142964 
3044c06356bSdh142964 		/* Print the reference count and priv */
305*5d562cecSMilos Muzik 		mdb_printf("] %-3d %0?lx %0?lx\n",
3064c06356bSdh142964 		    da->da_ref, da->da_cfg_priv, da->da_ppriv);
3074c06356bSdh142964 
308*5d562cecSMilos Muzik 		mdb_printf("       %p::print -ta dam_da_t\n", kdamda[i]);
3094c06356bSdh142964 	}
3104c06356bSdh142964 }
3114c06356bSdh142964 
3124c06356bSdh142964 /*ARGSUSED*/
3134c06356bSdh142964 int
damap(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)3144c06356bSdh142964 damap(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
3154c06356bSdh142964 {
3164c06356bSdh142964 	struct dam	*dam;
3174c06356bSdh142964 	void		**kdamda;
3184c06356bSdh142964 	int		kdamda_n;
3194c06356bSdh142964 
320*5d562cecSMilos Muzik 	if (!(flags & DCMD_ADDRSPEC)) {
321*5d562cecSMilos Muzik 		return (DCMD_ERR);
322*5d562cecSMilos Muzik 	}
323*5d562cecSMilos Muzik 
3244c06356bSdh142964 	dam = damap_get(addr, &kdamda, &kdamda_n);
3254c06356bSdh142964 	if (dam == NULL)
3264c06356bSdh142964 		return (DCMD_ERR);
3274c06356bSdh142964 
3284c06356bSdh142964 	damap_print(dam, kdamda, kdamda_n);
3294c06356bSdh142964 	damap_free(dam, kdamda, kdamda_n);
3304c06356bSdh142964 	return (DCMD_OK);
3314c06356bSdh142964 }
332