xref: /illumos-gate/usr/src/cmd/mdb/common/modules/genunix/damap.c (revision 8d0c3d29bb99f6521f2dc5058a7e4debebad7899)
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