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