OpenGrok

Cross Reference: sata.c
xref: /onnv/onnv-gate/usr/src/cmd/mdb/intel/modules/sata/sata.c
Home | History | Annotate | Line # | Download | only in sata
      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 
     27 #include <sys/mdb_modapi.h>
     28 #include <mdb/mdb_ks.h>
     29 #include <sys/modctl.h>
     30 #include <note.h>
     31 #include <sys/ddi_impldefs.h>
     32 #include <sys/ddidmareq.h>
     33 #include <sys/devops.h>
     34 #include <time.h>
     35 #include <sys/varargs.h>
     36 #include <sys/sata/sata_hba.h>
     37 
     38 /*
     39  * SATA trace debug walker/dcmd code
     40  */
     41 
     42 /*
     43  * Initialize the sata_trace_dmsg_t walker by either using the given starting
     44  * address, or reading the value of the kernel's sata_debug_rbuf pointer.
     45  * We also allocate a sata_trace_dmsg_t for storage, and save this using the
     46  * walk_data pointer.
     47  */
     48 static int
     49 sata_dmsg_walk_i(mdb_walk_state_t *wsp)
     50 {
     51 	uintptr_t rbuf_addr;
     52 	sata_trace_rbuf_t rbuf;
     53 
     54 	if (wsp->walk_addr == NULL) {
     55 		if (mdb_readvar(&rbuf_addr, "sata_debug_rbuf") == -1) {
     56 			mdb_warn("failed to read 'sata_debug_rbuf'");
     57 			return (WALK_ERR);
     58 		}
     59 
     60 		if (mdb_vread(&rbuf, sizeof (sata_trace_rbuf_t), rbuf_addr)
     61 		    == -1) {
     62 			mdb_warn("failed to read sata_trace_rbuf_t at %p",
     63 			    rbuf_addr);
     64 			return (WALK_ERR);
     65 		}
     66 
     67 		wsp->walk_addr = (uintptr_t)(sata_trace_dmsg_t *)rbuf.dmsgh;
     68 	}
     69 
     70 	/*
     71 	 * Save ptr to head of ring buffer to prevent looping.
     72 	 */
     73 	wsp->walk_arg = (void *)wsp->walk_addr;
     74 	wsp->walk_data = mdb_alloc(sizeof (sata_trace_dmsg_t), UM_SLEEP);
     75 	return (WALK_NEXT);
     76 }
     77 
     78 /*
     79  * At each step, read a sata_trace_dmsg_t into our private storage, and then
     80  * invoke the callback function.  We terminate when we reach a NULL next
     81  * pointer.
     82  */
     83 static int
     84 sata_dmsg_walk_s(mdb_walk_state_t *wsp)
     85 {
     86 	int status;
     87 
     88 	if (wsp->walk_addr == NULL)
     89 		return (WALK_DONE);
     90 
     91 	if (mdb_vread(wsp->walk_data, sizeof (sata_trace_dmsg_t),
     92 	    wsp->walk_addr) == -1) {
     93 		mdb_warn("failed to read sata_trace_dmsg_t at %p",
     94 		    wsp->walk_addr);
     95 		return (WALK_ERR);
     96 	}
     97 
     98 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
     99 	    wsp->walk_cbdata);
    100 
    101 	wsp->walk_addr =
    102 	    (uintptr_t)(((sata_trace_dmsg_t *)wsp->walk_data)->next);
    103 
    104 	/*
    105 	 * If we've looped then we're done.
    106 	 */
    107 	if (wsp->walk_addr == (uintptr_t)wsp->walk_arg)
    108 		wsp->walk_addr = NULL;
    109 
    110 	return (status);
    111 }
    112 
    113 /*
    114  * The walker's fini function is invoked at the end of each walk.  Since we
    115  * dynamically allocated a sata_trace_dmsg_t in sata_dmsg_walk_i, we must
    116  * free it now.
    117  */
    118 static void
    119 sata_dmsg_walk_f(mdb_walk_state_t *wsp)
    120 {
    121 	mdb_free(wsp->walk_data, sizeof (sata_trace_dmsg_t));
    122 }
    123 
    124 /*
    125  * This routine is used by the sata_dmsg_dump dcmd to dump content of
    126  * SATA trace ring buffer.
    127  */
    128 int
    129 sata_dmsg_dump(sata_trace_dmsg_t *addr, int print_pathname, uint_t *printed)
    130 {
    131 	sata_trace_dmsg_t	dmsg, *dmsgh = addr;
    132 	struct dev_info		dev;
    133 	char			drivername[MODMAXNAMELEN];
    134 	char			pathname[MAXPATHLEN];
    135 	char			merge[1024];
    136 
    137 	while (addr != NULL) {
    138 		if (mdb_vread(&dmsg, sizeof (dmsg), (uintptr_t)addr) !=
    139 		    sizeof (dmsg)) {
    140 			mdb_warn("failed to read message pointer in kernel");
    141 			return (DCMD_ERR);
    142 		}
    143 
    144 		if (dmsg.dip != NULL) {
    145 			if ((mdb_vread(&dev, sizeof (struct dev_info),
    146 			    (uintptr_t)dmsg.dip)) == -1) {
    147 				(void) mdb_snprintf(merge, sizeof (merge),
    148 				    "[%Y:%03d:%03d:%03d] : %s",
    149 				    dmsg.timestamp.tv_sec,
    150 				    (int)dmsg.timestamp.tv_nsec/1000000,
    151 				    (int)(dmsg.timestamp.tv_nsec/1000)%1000,
    152 				    (int)dmsg.timestamp.tv_nsec%1000,
    153 				    dmsg.buf);
    154 			} else {
    155 				(void) mdb_devinfo2driver((uintptr_t)dmsg.dip,
    156 				    drivername, sizeof (drivername));
    157 				(void) mdb_snprintf(merge, sizeof (merge),
    158 				    "[%Y:%03d:%03d:%03d] %s%d: %s",
    159 				    dmsg.timestamp.tv_sec,
    160 				    (int)dmsg.timestamp.tv_nsec/1000000,
    161 				    (int)(dmsg.timestamp.tv_nsec/1000)%1000,
    162 				    (int)dmsg.timestamp.tv_nsec%1000,
    163 				    drivername,
    164 				    dev.devi_instance,
    165 				    dmsg.buf);
    166 
    167 				if (print_pathname == TRUE) {
    168 					(void) mdb_ddi_pathname(
    169 					    (uintptr_t)dmsg.dip, pathname,
    170 					    sizeof (pathname));
    171 					mdb_printf("\n[%s]", pathname);
    172 				}
    173 			}
    174 		} else {
    175 			(void) mdb_snprintf(merge, sizeof (merge),
    176 			    "[%Y:%03d:%03d:%03d] : %s",
    177 			    dmsg.timestamp.tv_sec,
    178 			    (int)dmsg.timestamp.tv_nsec/1000000,
    179 			    (int)(dmsg.timestamp.tv_nsec/1000)%1000,
    180 			    (int)dmsg.timestamp.tv_nsec%1000,
    181 			    dmsg.buf);
    182 		}
    183 
    184 		mdb_printf("%s", merge);
    185 
    186 		if (printed != NULL) {
    187 			(*printed)++;
    188 		}
    189 
    190 		if (((addr = dmsg.next) == NULL) || (dmsg.next == dmsgh)) {
    191 			break;
    192 		}
    193 	}
    194 
    195 	return (DCMD_OK);
    196 }
    197 
    198 /*
    199  * 1. Process flag passed to sata_dmsg_dump dcmd.
    200  * 2. Obtain SATA trace ring buffer pointer.
    201  * 3. Pass SATA trace ring buffer pointer to sata_dmsg_dump()
    202  *    to dump content of SATA trace ring buffer.
    203  */
    204 int
    205 sata_rbuf_dump(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
    206 {
    207 	sata_trace_rbuf_t	rbuf;
    208 	uint_t		printed = 0; /* have we printed anything? */
    209 	int		print_pathname = FALSE;
    210 	int		rval = DCMD_OK;
    211 
    212 	if (argc > 1) {
    213 		return (DCMD_USAGE);
    214 	}
    215 
    216 	if (mdb_getopts(argc, argv,
    217 	    'a', MDB_OPT_SETBITS, TRUE, &print_pathname) != argc) {
    218 		return (DCMD_USAGE);
    219 	}
    220 
    221 	/*
    222 	 * If ring buffer address not provided try to obtain
    223 	 * it using sata_debug_rbuf global.
    224 	 */
    225 	if ((addr == NULL) || !(flags & DCMD_ADDRSPEC)) {
    226 		if (mdb_readvar(&addr, "sata_debug_rbuf") == -1) {
    227 			mdb_warn("Failed to read 'sata_debug_rbuf'.");
    228 			return (DCMD_ERR);
    229 		}
    230 	}
    231 
    232 	if (mdb_vread(&rbuf, sizeof (rbuf), addr) != sizeof (rbuf)) {
    233 		mdb_warn("Failed to read ring buffer in kernel.");
    234 		return (DCMD_ERR);
    235 	}
    236 
    237 	if (rbuf.dmsgh == NULL) {
    238 		mdb_printf("The sata trace ring buffer is empty.\n");
    239 		return (DCMD_OK);
    240 	}
    241 
    242 	rval = sata_dmsg_dump((sata_trace_dmsg_t *)rbuf.dmsgh,
    243 	    print_pathname, &printed);
    244 
    245 	if (rval != DCMD_OK) {
    246 		return (rval);
    247 	}
    248 
    249 	if (printed == 0) {
    250 		mdb_warn("Failed to read sata trace ring buffer.");
    251 		return (DCMD_ERR);
    252 	}
    253 
    254 	return (rval);
    255 }
    256 
    257 /*
    258  * MDB module linkage information:
    259  *
    260  * We declare a list of structures describing our dcmds, a list of structures
    261  * describing our walkers, and a function named _mdb_init to return a pointer
    262  * to our module information.
    263  */
    264 
    265 static const mdb_dcmd_t dcmds[] = {
    266 	{ "sata_dmsg_dump", "[-a]", "Dump sata trace debug messages",
    267 	    sata_rbuf_dump },
    268 	{ NULL }
    269 };
    270 
    271 static const mdb_walker_t walkers[] = {
    272 	{ "sata_dmsg",
    273 	    "walk ring buffer containing sata trace debug messages",
    274 	    sata_dmsg_walk_i, sata_dmsg_walk_s, sata_dmsg_walk_f },
    275 	{ NULL }
    276 };
    277 
    278 static const mdb_modinfo_t modinfo = {
    279 	MDB_API_VERSION, dcmds, walkers
    280 };
    281 
    282 const mdb_modinfo_t *
    283 _mdb_init(void)
    284 {
    285 	return (&modinfo);
    286 }
    287