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