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 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 * 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 594c06356bSdh142964 local_strfree(const char *s) 604c06356bSdh142964 { 614c06356bSdh142964 if (s) 624c06356bSdh142964 mdb_free((void *)s, strlen(s) + 1); 634c06356bSdh142964 } 644c06356bSdh142964 654c06356bSdh142964 static void 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 * 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 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 * 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 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 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