#include <mdb/mdb_modapi.h>
#include <sys/sysmacros.h>
#include <sys/sunddi.h>
#include <sys/damap.h>
#include <sys/damap_impl.h>
#include "damap.h"
void
damap_help(void)
{
mdb_printf("Print the damap at the address given.\n");
mdb_printf("\n");
mdb_printf("EXAMPLE: SCSI: To display the SCSI tgtmap damaps ");
mdb_printf("associated with a scsi HBA driver iport dip:\n");
mdb_printf("\n");
mdb_printf("::devbindings -q <driver_name>\n");
mdb_printf("\n");
mdb_printf("<iport-dip>::print struct dev_info devi_driver_data|");
mdb_printf("::print scsi_hba_tran_t tran_tgtmap|");
mdb_printf("::print impl_scsi_tgtmap_t ");
mdb_printf("tgtmap_dam[0] tgtmap_dam[1]|::damap\n");
}
static char *
local_strdup(const char *s)
{
if (s)
return (strcpy(mdb_alloc(strlen(s) + 1, UM_SLEEP), s));
else
return (NULL);
}
static void
local_strfree(const char *s)
{
if (s)
mdb_free((void *)s, strlen(s) + 1);
}
static void
bitset_free(bitset_t *bs, int embedded)
{
if (bs == NULL)
return;
if (bs->bs_set && bs->bs_words)
mdb_free(bs->bs_set, bs->bs_words * sizeof (ulong_t));
if (!embedded)
mdb_free(bs, sizeof (*bs));
}
static bitset_t *
bitset_get(uintptr_t bsaddr)
{
bitset_t *bs;
bs = mdb_zalloc(sizeof (*bs), UM_SLEEP);
if (mdb_vread(bs, sizeof (*bs), bsaddr) == -1) {
mdb_warn("couldn't read bitset 0x%p", bsaddr);
bitset_free(bs, 0);
return (NULL);
}
bsaddr = (uintptr_t)bs->bs_set;
bs->bs_set = mdb_alloc(bs->bs_words * sizeof (ulong_t), UM_SLEEP);
if (mdb_vread(bs->bs_set,
bs->bs_words * sizeof (ulong_t), bsaddr) == -1) {
mdb_warn("couldn't read bitset bs_set 0x%p", bsaddr);
bitset_free(bs, 0);
return (NULL);
}
return (bs);
}
static void
damap_free(struct dam *dam, void **kdamda, int kdamda_n)
{
int i;
struct i_ddi_soft_state *ss;
dam_da_t *da;
if (dam) {
ss = (struct i_ddi_soft_state *)dam->dam_da;
if (ss) {
if (ss->n_items && ss->array) {
for (i = 0; i < ss->n_items; i++) {
da = ss->array[i];
if (da == NULL)
continue;
local_strfree(da->da_addr);
mdb_free(da, sizeof (*da));
}
}
mdb_free(ss, sizeof (*ss));
}
bitset_free(&dam->dam_report_set, 1);
bitset_free(&dam->dam_stable_set, 1);
bitset_free(&dam->dam_active_set, 1);
local_strfree(dam->dam_name);
mdb_free(dam, sizeof (*dam));
}
if (kdamda)
mdb_free(kdamda, kdamda_n * sizeof (void *));
}
struct dam *
damap_get(uintptr_t damaddr, void ***pkdamda, int *pkdamda_n)
{
struct dam kdam;
char kstring[MAXPATHLEN];
struct i_ddi_soft_state kss;
void **kssarray = NULL;
int array_sz = 0;
struct dam *dam = NULL;
struct i_ddi_soft_state *ss;
bitset_t *bs;
dam_da_t *da;
int i;
if (mdb_vread(&kdam, sizeof (kdam), damaddr) == -1) {
mdb_warn("couldn't read dam 0x%p", damaddr);
goto err;
}
mdb_readstr(kstring, sizeof (kstring), (uintptr_t)kdam.dam_name);
if (mdb_vread(&kss, sizeof (kss), (uintptr_t)kdam.dam_da) == -1) {
mdb_warn("couldn't read dam dam_da 0x%p",
(uintptr_t)kdam.dam_da);
goto err;
}
array_sz = kss.n_items * sizeof (void *);
kssarray = mdb_alloc(array_sz, UM_SLEEP);
if (mdb_vread(kssarray, array_sz, (uintptr_t)kss.array) == -1) {
mdb_warn("couldn't read dam dam_da array 0x%p",
(uintptr_t)kss.array);
goto err;
}
dam = mdb_zalloc(sizeof (*dam), UM_SLEEP);
*dam = kdam;
dam->dam_name = NULL;
dam->dam_active_set.bs_set = NULL;
dam->dam_stable_set.bs_set = NULL;
dam->dam_report_set.bs_set = NULL;
dam->dam_da = NULL;
dam->dam_name = local_strdup(kstring);
bs = bitset_get(damaddr + (offsetof(struct dam, dam_active_set)));
if (bs) {
dam->dam_active_set = *bs;
mdb_free(bs, sizeof (*bs));
}
bs = bitset_get(damaddr + (offsetof(struct dam, dam_stable_set)));
if (bs) {
dam->dam_stable_set = *bs;
mdb_free(bs, sizeof (*bs));
}
bs = bitset_get(damaddr + (offsetof(struct dam, dam_report_set)));
if (bs) {
dam->dam_report_set = *bs;
mdb_free(bs, sizeof (*bs));
}
ss = mdb_zalloc(sizeof (struct i_ddi_soft_state), UM_SLEEP);
*ss = kss;
ss->next = NULL;
ss->array = mdb_zalloc(array_sz, UM_SLEEP);
dam->dam_da = ss;
for (i = 0; i < kss.n_items; i++) {
if (kssarray[i] == NULL)
continue;
da = ss->array[i] = mdb_zalloc(sizeof (*da), UM_SLEEP);
if (mdb_vread(da, sizeof (*da), (uintptr_t)kssarray[i]) == -1) {
mdb_warn("couldn't read dam dam_da %d 0x%p", i,
(uintptr_t)kss.array);
goto err;
}
mdb_readstr(kstring, sizeof (kstring), (uintptr_t)da->da_addr);
da->da_addr = local_strdup(kstring);
}
*pkdamda = kssarray;
*pkdamda_n = array_sz / sizeof (void *);
return (dam);
err: damap_free(dam, kssarray, array_sz / sizeof (void *));
*pkdamda = NULL;
*pkdamda_n = 0;
return (NULL);
}
static void
damap_print(struct dam *dam, void **kdamda, int kdamda_n)
{
struct i_ddi_soft_state *ss;
dam_da_t *da;
int i;
mdb_printf("%s:\n", dam->dam_name);
ss = (struct i_ddi_soft_state *)dam->dam_da;
if (ss == NULL)
return;
if ((ss->n_items == 0) || (ss->array == NULL))
return;
mdb_printf(" #: %-20s [ASR] ref config-private provider-private\n",
"address");
for (i = 0; i < ss->n_items; i++) {
da = ss->array[i];
if (da == NULL)
continue;
mdb_printf(" %3d: %-20s [", i, da->da_addr);
if (BT_TEST(dam->dam_active_set.bs_set, i))
mdb_printf("A");
else
mdb_printf(".");
if (BT_TEST(dam->dam_stable_set.bs_set, i))
mdb_printf("S");
else
mdb_printf(".");
if (BT_TEST(dam->dam_report_set.bs_set, i))
mdb_printf("R");
else
mdb_printf(".");
mdb_printf("] %-3d %0?lx %0?lx\n",
da->da_ref, da->da_cfg_priv, da->da_ppriv);
mdb_printf(" %p::print -ta dam_da_t\n", kdamda[i]);
}
}
int
damap(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
struct dam *dam;
void **kdamda;
int kdamda_n;
if (!(flags & DCMD_ADDRSPEC)) {
return (DCMD_ERR);
}
dam = damap_get(addr, &kdamda, &kdamda_n);
if (dam == NULL)
return (DCMD_ERR);
damap_print(dam, kdamda, kdamda_n);
damap_free(dam, kdamda, kdamda_n);
return (DCMD_OK);
}