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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * Copyright (c) 2018, Joyent, Inc.
29  */
30 
31 #include "ndievents.h"
32 #include <sys/sunndi.h>
33 #include <sys/ndi_impldefs.h>
34 #include <sys/dditypes.h>
35 #include <sys/ddi_impldefs.h>
36 #include <sys/sunddi.h>
37 #include <sys/param.h>
38 
39 
40 int
dip_to_pathname(struct dev_info * device,char * path,int buflen)41 dip_to_pathname(struct dev_info *device, char *path, int buflen)
42 {
43 	char *bp;
44 	char *addr;
45 	char addr_str[32];
46 	char nodename[MAXNAMELEN];
47 	struct dev_info devi_parent;
48 
49 	if (!device) {
50 		mdb_warn("Unable to access devinfo.");
51 		return (-1);
52 	}
53 
54 	if (device->devi_parent == NULL) {
55 		if (mdb_readstr(nodename, sizeof (nodename),
56 		    (uintptr_t)device->devi_node_name) == -1) {
57 			return (-1);
58 		}
59 
60 		if (sizeof (nodename) > (buflen - strlen(path))) {
61 			return (-1);
62 		}
63 
64 		strncpy(path, nodename, sizeof (nodename));
65 		return (0);
66 	}
67 
68 	if (mdb_vread(&devi_parent, sizeof (struct dev_info),
69 	    (uintptr_t)device->devi_parent) == -1) {
70 		mdb_warn("Unable to access devi_parent at %p",
71 		    (uintptr_t)device->devi_parent);
72 		return (-1);
73 	}
74 
75 	if (dip_to_pathname(&devi_parent, path, buflen) == -1) {
76 		return (-1);
77 	}
78 
79 	if (mdb_readstr(nodename, sizeof (nodename),
80 	    (uintptr_t)device->devi_node_name) == -1) {
81 		return (-1);
82 	}
83 
84 	if (device->devi_node_state < DS_INITIALIZED) {
85 		addr_str[0] = '\0';
86 	} else {
87 		addr = device->devi_addr;
88 		if (mdb_readstr(addr_str, sizeof (addr_str),
89 		    (uintptr_t)addr) == -1) {
90 			return (-1);
91 		}
92 	}
93 
94 	bp = path + strlen(path);
95 
96 	if (addr_str[0] == '\0') {
97 		(void) mdb_snprintf(bp, buflen - strlen(path), "/%s", nodename);
98 	} else {
99 		(void) mdb_snprintf(bp, buflen - strlen(path), "/%s@%s",
100 		    nodename, addr_str);
101 	}
102 	return (0);
103 
104 }
105 
106 /*ARGSUSED*/
107 int
ndi_callback_print(struct ndi_event_cookie * cookie,uint_t flags)108 ndi_callback_print(struct ndi_event_cookie *cookie, uint_t flags)
109 {
110 
111 	struct ndi_event_callbacks *callback_list;
112 	struct ndi_event_callbacks cb;
113 	char device_path[MAXPATHLEN];
114 	struct dev_info devi;
115 
116 	if (!cookie) {
117 		return (DCMD_ERR);
118 	}
119 
120 	callback_list = cookie->callback_list;
121 
122 	while (callback_list != NULL) {
123 		if (mdb_vread(&cb, sizeof (struct ndi_event_callbacks),
124 		    (uintptr_t)callback_list) == -1) {
125 			mdb_warn("Could not read callback structure at"
126 			    " %p", callback_list);
127 			return (DCMD_ERR);
128 		}
129 
130 		if (mdb_vread(&devi, sizeof (struct dev_info),
131 		    (uintptr_t)cb.ndi_evtcb_dip) == -1) {
132 			mdb_warn("Could not read devinfo structure at"
133 			    " %p", cb.ndi_evtcb_dip);
134 			return (DCMD_ERR);
135 		}
136 
137 		if (dip_to_pathname(&devi, device_path, sizeof (device_path))
138 		    == -1) {
139 			return (DCMD_ERR);
140 		}
141 
142 		mdb_printf("\t\tCallback Registered By: %s\n", device_path);
143 		mdb_printf("\t\t  Callback Address:\t%-?p\n"
144 		    "\t\t  Callback Function:\t%-p\n"
145 		    "\t\t  Callback Args:\t%-?p\n"
146 		    "\t\t  Callback Cookie:\t%-?p\n",
147 		    callback_list, cb.ndi_evtcb_callback, cb.ndi_evtcb_arg,
148 		    cb.ndi_evtcb_cookie);
149 
150 		callback_list = cb.ndi_evtcb_next;
151 
152 	}
153 
154 	return (DCMD_OK);
155 }
156 
157 int
ndi_event_print(struct ndi_event_hdl * hdl,uint_t flags)158 ndi_event_print(struct ndi_event_hdl *hdl, uint_t flags)
159 {
160 
161 	struct	ndi_event_definition def;
162 	struct	ndi_event_cookie cookie;
163 	struct	ndi_event_cookie *cookie_list;
164 	char	ndi_event_name[256];
165 
166 	if (!hdl)
167 		return (DCMD_ERR);
168 
169 	cookie_list = hdl->ndi_evthdl_cookie_list;
170 	if (cookie_list == NULL) {
171 		mdb_printf("\tNo cookies defined for this handle.\n");
172 		return (DCMD_OK);
173 	}
174 
175 	while (cookie_list != NULL) {
176 		if (mdb_vread(&cookie, sizeof (struct ndi_event_cookie),
177 		    (uintptr_t)cookie_list) == -1) {
178 			mdb_warn("Unable to access cookie list");
179 			return (DCMD_ERR);
180 		}
181 
182 		if (mdb_vread(&def, sizeof (struct ndi_event_definition),
183 		    (uintptr_t)cookie.definition) == -1) {
184 			mdb_warn("Unable to access definition at %p",
185 			    cookie.definition);
186 			return (DCMD_ERR);
187 		}
188 
189 		if (mdb_readstr(ndi_event_name, sizeof (ndi_event_name),
190 		    (uintptr_t)def.ndi_event_name) == -1) {
191 			mdb_warn("Unable to read cookie name.");
192 			return (DCMD_ERR);
193 		}
194 
195 		mdb_printf("\tCookie(%s %p) :Plevel(%d)\n\tddip(%p)"
196 		    " : Attr(%d)\n",
197 		    ndi_event_name, cookie_list, def.ndi_event_plevel,
198 		    cookie.ddip, def.ndi_event_attributes);
199 
200 		ndi_callback_print(&cookie, flags);
201 		cookie_list = cookie.next_cookie;
202 
203 	}
204 	return (0);
205 }
206 
207 /*ARGSUSED*/
208 int
ndi_event_hdl(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)209 ndi_event_hdl(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
210 {
211 
212 	struct dev_info devi;
213 	struct ndi_event_hdl handle;
214 	char path[MAXPATHLEN];
215 	int done;
216 
217 	if (!(flags & DCMD_ADDRSPEC)) {
218 		return (DCMD_USAGE);
219 	}
220 
221 	if (mdb_vread(&handle, sizeof (struct ndi_event_hdl), addr) == -1) {
222 		mdb_warn("failed to read ndi_event_hdl at %p", addr);
223 		return (DCMD_ERR);
224 	}
225 
226 	if (mdb_vread(&devi, sizeof (struct dev_info),
227 	    (uintptr_t)handle.ndi_evthdl_dip) == -1) {
228 		mdb_warn("failed to read devinfo node at %p",
229 		    handle.ndi_evthdl_dip);
230 		return (DCMD_ERR);
231 	}
232 
233 	if (dip_to_pathname(&devi, path, sizeof (path)) == -1) {
234 		return (DCMD_ERR);
235 	}
236 
237 	done = 0;
238 	while (!done) {
239 
240 		mdb_printf("%<b>Handle%</b> (%p) :%<b> Path%</b> (%s) : %<b>"
241 		    "dip %</b>(%p) \n", addr, path, handle.ndi_evthdl_dip);
242 
243 		mdb_printf("mutexes:	handle(%p)	callback(%p)\n",
244 		    handle.ndi_evthdl_mutex, handle.ndi_evthdl_cb_mutex);
245 
246 		ndi_event_print(&handle, flags);
247 
248 		if (handle.ndi_next_hdl == NULL) {
249 			done = 1;
250 		} else {
251 			addr = (uintptr_t)handle.ndi_next_hdl;
252 			if (mdb_vread(&handle, sizeof (struct ndi_event_hdl),
253 			    (uintptr_t)addr) == -1) {
254 				mdb_warn("failed to read ndi_event_hdl at %p",
255 				    addr);
256 				break;
257 			}
258 
259 		}
260 	}
261 
262 	return (0);
263 }
264