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