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
damap_help(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 *
local_strdup(const char * s)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
local_strfree(const char * s)59 local_strfree(const char *s)
60 {
61 if (s)
62 mdb_free((void *)s, strlen(s) + 1);
63 }
64
65 static void
bitset_free(bitset_t * bs,int embedded)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 *
bitset_get(uintptr_t bsaddr)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
damap_free(struct dam * dam,void ** kdamda,int kdamda_n)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 *
damap_get(uintptr_t damaddr,void *** pkdamda,int * pkdamda_n)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
damap_print(struct dam * dam,void ** kdamda,int kdamda_n)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
damap(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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