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