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
  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
 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
 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
 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)
 228             == -1) {
 229                 mdb_warn("failed to read devinfo node at %p",
 230                     handle.ndi_evthdl_dip);
 231                 return (DCMD_ERR);
 232         }
 233 
 234         if (dip_to_pathname(&devi, path, sizeof (path)) == -1) {
 235                 return (DCMD_ERR);
 236         }
 237 
 238         done = 0;
 239         while (!done) {
 240 
 241                 mdb_printf("%<b>Handle%</b> (%p) :%<b> Path%</b> (%s) : %<b>"
 242                     "dip %</b>(%p) \n", addr, path, handle.ndi_evthdl_dip);
 243 
 244                 mdb_printf("mutexes:    handle(%p)      callback(%p)\n",
 245                     handle.ndi_evthdl_mutex, handle.ndi_evthdl_cb_mutex);
 246 
 247                 ndi_event_print(&handle, flags);
 248 
 249                 if (handle.ndi_next_hdl == NULL) {
 250                         done = 1;
 251                 } else {
 252                         addr = (uintptr_t)handle.ndi_next_hdl;
 253                         if (mdb_vread(&handle, sizeof (struct ndi_event_hdl),
 254                             (uintptr_t)addr) == -1) {
 255                             mdb_warn("failed to read ndi_event_hdl at %p",
 256                             addr);
 257                             break;
 258                         }
 259 
 260                 }
 261         }
 262 
 263         return (0);
 264 }