1 /* 2 * CDDL HEADER START 3 * 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. 7 * 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. 12 * 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] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 #include <mdb/mdb_modapi.h> 26 #include <sys/sysmacros.h> 27 #include <sys/sunddi.h> 28 #include <sys/damap.h> 29 #include <sys/damap_impl.h> 30 31 #include "damap.h" 32 33 void 34 damap_help(void) 35 { 36 mdb_printf("Print the damap at the address given.\n"); 37 mdb_printf("\n"); 38 mdb_printf("EXAMPLE: SCSI: To display the SCSI tgtmap damaps "); 39 mdb_printf("associated with a scsi HBA driver iport dip:\n"); 40 mdb_printf("\n"); 41 mdb_printf("::devbindings -q <driver_name>\n"); 42 mdb_printf("\n"); 43 mdb_printf("<iport-dip>::print struct dev_info devi_driver_data|"); 44 mdb_printf("::print scsi_hba_tran_t tran_tgtmap|"); 45 mdb_printf("::print impl_scsi_tgtmap_t "); 46 mdb_printf("tgtmap_dam[0] tgtmap_dam[1]|::damap\n"); 47 } 48 49 static char * 50 local_strdup(const char *s) 51 { 52 if (s) 53 return (strcpy(mdb_alloc(strlen(s) + 1, UM_SLEEP), s)); 54 else 55 return (NULL); 56 } 57 58 static void 59 local_strfree(const char *s) 60 { 61 if (s) 62 mdb_free((void *)s, strlen(s) + 1); 63 } 64 65 static void 66 bitset_free(bitset_t *bs, int embedded) 67 { 68 if (bs == NULL) 69 return; 70 if (bs->bs_set && bs->bs_words) 71 mdb_free(bs->bs_set, bs->bs_words * sizeof (ulong_t)); 72 if (!embedded) 73 mdb_free(bs, sizeof (*bs)); /* not embedded, free */ 74 } 75 76 static bitset_t * 77 bitset_get(uintptr_t bsaddr) 78 { 79 bitset_t *bs; 80 81 bs = mdb_zalloc(sizeof (*bs), UM_SLEEP); 82 if (mdb_vread(bs, sizeof (*bs), bsaddr) == -1) { 83 mdb_warn("couldn't read bitset 0x%p", bsaddr); 84 bitset_free(bs, 0); 85 return (NULL); 86 } 87 88 bsaddr = (uintptr_t)bs->bs_set; 89 bs->bs_set = mdb_alloc(bs->bs_words * sizeof (ulong_t), UM_SLEEP); 90 if (mdb_vread(bs->bs_set, 91 bs->bs_words * sizeof (ulong_t), bsaddr) == -1) { 92 mdb_warn("couldn't read bitset bs_set 0x%p", bsaddr); 93 bitset_free(bs, 0); 94 return (NULL); 95 } 96 return (bs); 97 98 } 99 100 static void 101 damap_free(struct dam *dam, void **kdamda, int kdamda_n) 102 { 103 int i; 104 struct i_ddi_soft_state *ss; 105 dam_da_t *da; 106 107 if (dam) { 108 /* free in dam_da_t softstate */ 109 ss = (struct i_ddi_soft_state *)dam->dam_da; 110 if (ss) { 111 if (ss->n_items && ss->array) { 112 for (i = 0; i < ss->n_items; i++) { 113 da = ss->array[i]; 114 if (da == NULL) 115 continue; 116 local_strfree(da->da_addr); 117 mdb_free(da, sizeof (*da)); 118 } 119 } 120 121 mdb_free(ss, sizeof (*ss)); 122 } 123 124 /* free dam_active/stable/report_set embedded in dam */ 125 bitset_free(&dam->dam_report_set, 1); 126 bitset_free(&dam->dam_stable_set, 1); 127 bitset_free(&dam->dam_active_set, 1); 128 129 /* free dam_name */ 130 local_strfree(dam->dam_name); 131 132 /* free dam */ 133 mdb_free(dam, sizeof (*dam)); 134 } 135 136 if (kdamda) 137 mdb_free(kdamda, kdamda_n * sizeof (void *)); 138 } 139 140 /* 141 * The dam implementation uses a number of different abstractions. Given a 142 * pointer to a damap_t, this function make an mdb instantiation of the dam - 143 * many, but not all, of the different abstractions used in the dam 144 * implementation are also instantiated in mdb. This means that callers of 145 * damap_get can perform some (but not all) types of structure pointer 146 * traversals. 147 */ 148 struct dam * 149 damap_get(uintptr_t damaddr, void ***pkdamda, int *pkdamda_n) 150 { 151 /* variables that hold instantiation read from kernel */ 152 struct dam kdam; 153 char kstring[MAXPATHLEN]; 154 struct i_ddi_soft_state kss; 155 void **kssarray = NULL; 156 int array_sz = 0; 157 158 /* variables that hold mdb instantiation */ 159 struct dam *dam = NULL; 160 struct i_ddi_soft_state *ss; 161 bitset_t *bs; 162 dam_da_t *da; 163 164 int i; 165 166 /* read kernel: dam */ 167 if (mdb_vread(&kdam, sizeof (kdam), damaddr) == -1) { 168 mdb_warn("couldn't read dam 0x%p", damaddr); 169 goto err; 170 } 171 172 /* read kernel: dam->dam_name */ 173 mdb_readstr(kstring, sizeof (kstring), (uintptr_t)kdam.dam_name); 174 175 /* read kernel: dam->dam_da (softstate) */ 176 if (mdb_vread(&kss, sizeof (kss), (uintptr_t)kdam.dam_da) == -1) { 177 mdb_warn("couldn't read dam dam_da 0x%p", 178 (uintptr_t)kdam.dam_da); 179 goto err; 180 } 181 182 /* read kernel ((struct i_ddi_soft_state *)dam->dam_da)->array */ 183 array_sz = kss.n_items * sizeof (void *); 184 kssarray = mdb_alloc(array_sz, UM_SLEEP); 185 if (mdb_vread(kssarray, array_sz, (uintptr_t)kss.array) == -1) { 186 mdb_warn("couldn't read dam dam_da array 0x%p", 187 (uintptr_t)kss.array); 188 goto err; 189 } 190 191 /* 192 * Produce mdb instantiation of kernel data structures. 193 * 194 * Structure copy kdam to dam, then clear out pointers in dam (some 195 * will be filled in by mdb instantiation code below). 196 */ 197 dam = mdb_zalloc(sizeof (*dam), UM_SLEEP); 198 *dam = kdam; 199 dam->dam_name = NULL; 200 201 dam->dam_active_set.bs_set = NULL; 202 dam->dam_stable_set.bs_set = NULL; 203 dam->dam_report_set.bs_set = NULL; 204 205 dam->dam_da = NULL; 206 /* dam_addr_hash, dam_taskqp, dam_kstatp left as kernel addresses */ 207 208 /* fill in dam_name */ 209 dam->dam_name = local_strdup(kstring); 210 211 /* fill in dam_active/stable/report_set embedded in the dam */ 212 bs = bitset_get(damaddr + (offsetof(struct dam, dam_active_set))); 213 if (bs) { 214 dam->dam_active_set = *bs; 215 mdb_free(bs, sizeof (*bs)); 216 } 217 bs = bitset_get(damaddr + (offsetof(struct dam, dam_stable_set))); 218 if (bs) { 219 dam->dam_stable_set = *bs; 220 mdb_free(bs, sizeof (*bs)); 221 } 222 bs = bitset_get(damaddr + (offsetof(struct dam, dam_report_set))); 223 if (bs) { 224 dam->dam_report_set = *bs; 225 mdb_free(bs, sizeof (*bs)); 226 } 227 228 /* fill in dam_da_t softstate */ 229 ss = mdb_zalloc(sizeof (struct i_ddi_soft_state), UM_SLEEP); 230 *ss = kss; 231 ss->next = NULL; 232 ss->array = mdb_zalloc(array_sz, UM_SLEEP); 233 dam->dam_da = ss; 234 for (i = 0; i < kss.n_items; i++) { 235 if (kssarray[i] == NULL) 236 continue; 237 da = ss->array[i] = mdb_zalloc(sizeof (*da), UM_SLEEP); 238 if (mdb_vread(da, sizeof (*da), (uintptr_t)kssarray[i]) == -1) { 239 mdb_warn("couldn't read dam dam_da %d 0x%p", i, 240 (uintptr_t)kss.array); 241 goto err; 242 } 243 /* da_nvl, da_ppriv_rpt, da_nvl_rpt left as kernel addresses */ 244 245 /* read kernel: da->da_addr */ 246 mdb_readstr(kstring, sizeof (kstring), (uintptr_t)da->da_addr); 247 da->da_addr = local_strdup(kstring); 248 } 249 250 /* return array of kernel dam_da_t pointers associated with each id */ 251 *pkdamda = kssarray; 252 *pkdamda_n = array_sz / sizeof (void *); 253 254 /* return pointer to mdb instantiation of the dam */ 255 return (dam); 256 257 err: damap_free(dam, kssarray, array_sz / sizeof (void *)); 258 *pkdamda = NULL; 259 *pkdamda_n = 0; 260 return (NULL); 261 } 262 263 /*ARGSUSED*/ 264 static void 265 damap_print(struct dam *dam, void **kdamda, int kdamda_n) 266 { 267 struct i_ddi_soft_state *ss; 268 dam_da_t *da; 269 int i; 270 271 mdb_printf("%s:\n", dam->dam_name); 272 273 ss = (struct i_ddi_soft_state *)dam->dam_da; 274 if (ss == NULL) 275 return; 276 277 if ((ss->n_items == 0) || (ss->array == NULL)) 278 return; 279 280 mdb_printf(" #: %-20s [ASR] ref config-private provider-private\n", 281 "address"); 282 for (i = 0; i < ss->n_items; i++) { 283 da = ss->array[i]; 284 if (da == NULL) 285 continue; 286 287 /* Print index and address. */ 288 mdb_printf(" %3d: %-20s [", i, da->da_addr); 289 290 /* Print shorthand of Active/Stable/Report set membership */ 291 if (BT_TEST(dam->dam_active_set.bs_set, i)) 292 mdb_printf("A"); 293 else 294 mdb_printf("."); 295 if (BT_TEST(dam->dam_stable_set.bs_set, i)) 296 mdb_printf("S"); 297 else 298 mdb_printf("."); 299 if (BT_TEST(dam->dam_report_set.bs_set, i)) 300 mdb_printf("R"); 301 else 302 mdb_printf("."); 303 304 /* Print the reference count and priv */ 305 mdb_printf("] %-3d %0?lx %0?lx\n", 306 da->da_ref, da->da_cfg_priv, da->da_ppriv); 307 308 mdb_printf(" %p::print -ta dam_da_t\n", kdamda[i]); 309 } 310 } 311 312 /*ARGSUSED*/ 313 int 314 damap(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 315 { 316 struct dam *dam; 317 void **kdamda; 318 int kdamda_n; 319 320 if (!(flags & DCMD_ADDRSPEC)) { 321 return (DCMD_ERR); 322 } 323 324 dam = damap_get(addr, &kdamda, &kdamda_n); 325 if (dam == NULL) 326 return (DCMD_ERR); 327 328 damap_print(dam, kdamda, kdamda_n); 329 damap_free(dam, kdamda, kdamda_n); 330 return (DCMD_OK); 331 } 332