/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <gelf.h>
#include <sys/mdb_modapi.h>
#define UHCI_TD 0
/* Prototypes */
int uhci_td_walk_init(mdb_walk_state_t *);
int uhci_td_walk_step(mdb_walk_state_t *);
int uhci_qh_walk_init(mdb_walk_state_t *);
int uhci_qh_walk_step(mdb_walk_state_t *);
/*
* Callback for find_uhci_statep (called back from walk "softstate" in
* find_uhci_statep).
*
* - uhci_instancep is the value of the current pointer in the array of soft
* state instance pointers (see i_ddi_soft_state in ddi_impldefs.h)
* - local_ss is a pointer to the copy of the i_ddi_soft_state in local space
* - cb_arg is a pointer to the cb arg (an instance of state_find_data).
*
* For the current uchi_state_t*, see if the td address is in its pool.
*
* Returns WALK_NEXT on success (match not found yet), WALK_ERR on errors.
*
* WALK_DONE is returned, cb_data.found is set to TRUE, and
* *cb_data.fic_uhci_statep is filled in with the contents of the state
* struct in core. This forces the walk to terminate.
*/
typedef struct find_instance_struct {
/*ARGSUSED*/
static int
{
uhci_instancep) == -1) {
return (-1);
}
-1) {
mdb_warn("failed to read uhci_td_pool_size");
return (-1);
}
-1) {
mdb_warn("failed to read uhci_td_pool_size");
return (-1);
}
/*
* See if the addr is within the appropriate pool for this instance.
*/
td_pool_size - sizeof (uhci_td_t)))) ||
qh_pool_size - sizeof (queue_head_t))))) {
return (WALK_DONE);
}
return (WALK_NEXT);
}
/*
*
* - td_qh: a pointer to a uhci td or qh
* - uhci_statep, pointer to a uhci_state_t, to be filled in with data from
* the found instance of uhci_state_t.
*
* and so cannot be found with this method.
*
* Returns 0 on success (no match found), 1 on success (match found),
* -1 on errors.
*/
static int
{
if (uhci_statep == NULL) {
mdb_warn("failed to find uhci statep: "
"NULL uhci_statep param\n");
return (-1);
}
"uhci_statep") == -1) {
mdb_warn("failed to read uhci_statep");
return (-1);
}
/*
* Walk all instances of uhci.
* The callback func checks if td_qh belongs to a given instance
* of uhci.
*/
uhci_ss) != 0) {
mdb_warn("failed to walk softstate");
return (-1);
}
return (1);
}
return (0);
}
/*
* Dump a UHCI TD (transaction descriptor);
* or (-d) the chain of TDs starting with the one specified.
*/
int
{
if (!(flags & DCMD_ADDRSPEC))
return (DCMD_USAGE);
if (addr & ~QH_LINK_PTR_MASK) {
mdb_warn("address must be on a 16-byte boundary.\n");
return (DCMD_ERR);
}
return (DCMD_USAGE);
}
if (depth_flag) {
mdb_warn("failed to walk 'uhci_td'");
return (DCMD_ERR);
}
return (DCMD_OK);
}
mdb_warn("failed to find uhci_statep");
return (DCMD_ERR);
}
return (DCMD_ERR);
}
mdb_printf(" link_ptr (paddr) : %-8x "
"(vaddr) : %p\n",
/* Note: uhcip needed by TD_VADDR macro */
} else {
mdb_printf(" link_ptr (paddr) : %-8x\n",
}
mdb_printf(" qh_td_prev : %?p "
"tw_td_next : %?p\n",
mdb_printf(" outst_td_prev : %?p "
"outst_td_next : %?p\n",
mdb_printf(" tw : %?p "
mdb_printf(" isoc_next : %?p "
mdb_printf(" isoc_pkt_index : %0x "
mdb_printf(" --> Link pointer = NULL\n");
return (DCMD_ERR);
} else {
/* Inform user if link is to a TD or QH. */
mdb_printf(" "
"--> Link pointer invalid (terminate bit set).\n");
} else {
mdb_printf(" "
"--> Link pointer points to a QH.\n");
} else {
mdb_printf(" "
"--> Link pointer points to a TD.\n");
}
}
}
return (DCMD_OK);
}
/*
* Dump a UHCI QH (queue head).
* -d also dump the chain of TDs starting with the one specified.
*/
int
{
if (!(flags & DCMD_ADDRSPEC))
return (DCMD_USAGE);
if (addr & ~QH_LINK_PTR_MASK) {
mdb_warn("address must be on a 16-byte boundary.\n");
return (DCMD_ERR);
}
return (DCMD_USAGE);
}
if (breadth_flag) {
if (depth_flag) {
new_argc = 1;
}
addr)) != 0) {
mdb_warn("failed to walk 'uhci_qh'");
return (DCMD_ERR);
}
return (DCMD_OK);
}
mdb_warn("failed to find uhci_statep");
return (DCMD_ERR);
}
return (DCMD_ERR);
}
mdb_printf(" link_ptr (paddr) : %08x "
"(vaddr) : %p\n",
/* Note: uhcip needed by QH_VADDR macro */
} else {
" link_ptr (paddr) : %08x\n",
}
mdb_printf(" element_ptr (paddr) : %08x "
"(vaddr) : %p\n",
/* Note: uhcip needed by TD_VADDR macro */
} else {
}
mdb_printf(" node : %04x "
"flag : %04x\n",
mdb_printf(" prev_qh : %?p "
"td_tailp : %?p\n",
mdb_printf(" --> Link pointer = NULL\n");
return (DCMD_ERR);
} else {
/* Inform user if next link is a TD or QH. */
mdb_printf(" "
"--> Link pointer invalid (terminate bit set).\n");
} else {
mdb_printf(" "
"--> Link pointer points to a QH.\n");
} else {
/* Should never happen. */
mdb_warn(" "
"--> Link pointer points to a TD.\n");
return (DCMD_ERR);
}
}
}
mdb_printf(" element_ptr = NULL\n");
return (DCMD_ERR);
} else {
/* Inform user if next element is a TD or QH. */
mdb_printf(" "
"-->Element pointer invalid (terminate bit set)."
"\n");
return (DCMD_OK);
} else {
mdb_printf(" "
"--> Element pointer points to a QH.\n");
/* Should never happen in UHCI implementation */
return (DCMD_ERR);
} else {
mdb_printf(" "
"--> Element pointer points to a TD.\n");
}
}
}
/*
* If the user specified the -d (depth) option,
* dump all TDs linked to this TD via the element_ptr.
*/
if (depth_flag) {
/* Traverse and display all the TDs in the chain */
QH_LINK_PTR_MASK))) == -1) {
mdb_warn("failed to walk 'uhci_td'");
return (DCMD_ERR);
}
}
return (DCMD_OK);
}
/*
* Walk a list of UHCI Transaction Descriptors (td's).
* Stop at the end of the list, or if the next element in the list is a
* queue head (qh).
* User must specify the address of the first td to look at.
*/
int
{
return (DCMD_USAGE);
}
/*
* Read the uhci_state_t for the instance of uhci
* using this td address into buf pointed to by walk_arg.
*/
mdb_warn("failed to find uhci_statep");
return (WALK_ERR);
}
return (WALK_NEXT);
}
/*
* At each step, read a TD into our private storage, and then invoke
* the callback function. We terminate when we reach a QH, or
* link_ptr is NULL.
*/
int
{
int status;
== -1) {
return (WALK_DONE);
}
wsp->walk_cbdata);
/* Next td. */
/* Check if we're at the last element */
return (WALK_DONE);
/* Make sure next element is a TD. If a QH, stop. */
== HC_QUEUE_HEAD) {
return (WALK_DONE);
}
/* Strip terminate etc. bits. */
return (WALK_DONE);
/*
* Convert link_ptr paddr to vaddr
* Note: uhcip needed by TD_VADDR macro
*/
return (status);
}
/*
* Walk a list of UHCI Queue Heads (qh's).
* Stop at the end of the list, or if the next element in the list is a
* Transaction Descriptor (td).
* User must specify the address of the first qh to look at.
*/
int
{
return (DCMD_USAGE);
/*
* Read the uhci_state_t for the instance of uhci
* using this td address into buf pointed to by walk_arg.
*/
mdb_warn("failed to find uhci_statep");
return (WALK_ERR);
}
return (WALK_NEXT);
}
/*
* At each step, read a QH into our private storage, and then invoke
* the callback function. We terminate when we reach a QH, or
* link_ptr is NULL.
*/
int
{
int status;
return (WALK_DONE);
== -1) {
return (WALK_DONE);
}
wsp->walk_cbdata);
/* Next QH. */
/* Check if we're at the last element */
return (WALK_DONE);
}
/* Make sure next element is a QH. If a TD, stop. */
!= HC_QUEUE_HEAD) {
return (WALK_DONE);
}
/* Strip terminate etc. bits. */
return (WALK_DONE);
/*
* Convert link_ptr paddr to vaddr
* Note: uhcip needed by QH_VADDR macro
*/
return (status);
}
/*
* MDB module linkage information:
*
* We declare a list of structures describing our dcmds, and a function
* named _mdb_init to return a pointer to our module information.
*/
{ NULL }
};
{ "uhci_td", "walk list of UHCI TD structures",
NULL },
{ "uhci_qh", "walk list of UHCI QH structures",
NULL },
{ NULL }
};
};
const mdb_modinfo_t *
_mdb_init(void)
{
return (&modinfo);
}