Print this page
4500 mptsas_hash_traverse() is unsafe, leads to missing devices
Reviewed by: Hans Rosenfeld <hans.rosenfeld@nexenta.com>
Approved by: Albert Lee <trisk@nexenta.com>
4499 ::mptsas should show slot/enclosure for targets
Reviewed by: Hans Rosenfeld <hans.rosenfeld@nexenta.com>
Approved by: Albert Lee <trisk@nexenta.com>
*** 21,34 ****
--- 21,39 ----
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
+ /*
+ * Copyright 2014 Joyent, Inc. All rights reserved.
+ */
+
#include <limits.h>
#include <sys/mdb_modapi.h>
#include <sys/sysinfo.h>
#include <sys/sunmdi.h>
+ #include <sys/list.h>
#include <sys/scsi/scsi.h>
#pragma pack(1)
#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_type.h>
#include <sys/scsi/adapters/mpt_sas/mpi/mpi2.h>
*** 39,51 ****
#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_raid.h>
#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_tool.h>
#pragma pack()
#include <sys/scsi/adapters/mpt_sas/mptsas_var.h>
struct {
-
int value;
char *text;
} devinfo_array[] = {
{ MPI2_SAS_DEVICE_INFO_SEP, "SEP" },
{ MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE, "ATAPI device" },
--- 44,56 ----
#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_raid.h>
#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_tool.h>
#pragma pack()
#include <sys/scsi/adapters/mpt_sas/mptsas_var.h>
+ #include <sys/scsi/adapters/mpt_sas/mptsas_hash.h>
struct {
int value;
char *text;
} devinfo_array[] = {
{ MPI2_SAS_DEVICE_INFO_SEP, "SEP" },
{ MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE, "ATAPI device" },
*** 59,81 ****
{ MPI2_SAS_DEVICE_INFO_STP_INITIATOR, "STP init" },
{ MPI2_SAS_DEVICE_INFO_SMP_INITIATOR, "SMP init" },
{ MPI2_SAS_DEVICE_INFO_SATA_HOST, "SATA host" }
};
- static int
- atoi(const char *p)
- {
- int n;
- int c = *p++;
-
- for (n = 0; c >= '0' && c <= '9'; c = *p++) {
- n *= 10; /* two steps to avoid unnecessary overflow */
- n += '0' - c; /* accum neg to avoid surprises at MAX */
- }
- return (-n);
- }
-
int
construct_path(uintptr_t addr, char *result)
{
struct dev_info d;
char devi_node[PATH_MAX];
--- 64,73 ----
*** 114,125 ****
if (mdb_vread(&pi, sizeof (pi), addr) == -1) {
mdb_warn("couldn't read mdi_pathinfo");
return (DCMD_ERR);
}
mdb_readstr(string, sizeof (string), (uintptr_t)pi.pi_addr);
! mdi_target = atoi(string);
! mdi_lun = atoi(strchr(string, ',')+1);
if (target != mdi_target)
return (0);
if (mdb_vread(&c, sizeof (c), (uintptr_t)pi.pi_client) == -1) {
mdb_warn("couldn't read mdi_client");
--- 106,117 ----
if (mdb_vread(&pi, sizeof (pi), addr) == -1) {
mdb_warn("couldn't read mdi_pathinfo");
return (DCMD_ERR);
}
mdb_readstr(string, sizeof (string), (uintptr_t)pi.pi_addr);
! mdi_target = (int)mdb_strtoull(string);
! mdi_lun = (int)mdb_strtoull(strchr(string, ',') + 1);
if (target != mdi_target)
return (0);
if (mdb_vread(&c, sizeof (c), (uintptr_t)pi.pi_client) == -1) {
mdb_warn("couldn't read mdi_client");
*** 211,325 ****
mdb_printf("]\n");
}
void
! display_ports(struct mptsas m)
{
int i;
mdb_printf("\n");
mdb_printf("phy number and port mapping table\n");
for (i = 0; i < MPTSAS_MAX_PHYS; i++) {
! if (m.m_phy_info[i].attached_devhdl) {
mdb_printf("phy %x --> port %x, phymask %x,"
! "attached_devhdl %x\n", i, m.m_phy_info[i].port_num,
! m.m_phy_info[i].phy_mask,
! m.m_phy_info[i].attached_devhdl);
}
}
mdb_printf("\n");
}
! static void *
! hash_traverse(mptsas_hash_table_t *hashtab, int pos, int alloc_size)
{
! mptsas_hash_node_t *this = NULL;
! mptsas_hash_node_t h;
! void *ret = NULL;
! if (pos == MPTSAS_HASH_FIRST) {
! hashtab->line = 0;
! hashtab->cur = NULL;
! this = hashtab->head[0];
! } else {
! if (hashtab->cur == NULL) {
return (NULL);
- } else {
- mdb_vread(&h, sizeof (h), (uintptr_t)hashtab->cur);
- this = h.next;
- }
- }
! while (this == NULL) {
! hashtab->line++;
! if (hashtab->line >= MPTSAS_HASH_ARRAY_SIZE) {
! /* the traverse reaches the end */
! hashtab->cur = NULL;
return (NULL);
! } else {
! this = hashtab->head[hashtab->line];
}
- }
- hashtab->cur = this;
! if (mdb_vread(&h, sizeof (h), (uintptr_t)this) == -1) {
! mdb_warn("couldn't read hashtab");
return (NULL);
}
! ret = mdb_alloc(alloc_size, UM_SLEEP);
! if (mdb_vread(ret, alloc_size, (uintptr_t)h.data) == -1) {
! mdb_warn("couldn't read hashdata");
! return (NULL);
! }
! return (ret);
}
void
! display_targets(struct mptsas_slots *s)
{
mptsas_target_t *ptgt;
mptsas_smp_t *psmp;
mdb_printf("\n");
mdb_printf("The SCSI target information\n");
! ptgt = (mptsas_target_t *)hash_traverse(&s->m_tgttbl,
! MPTSAS_HASH_FIRST, sizeof (mptsas_target_t));
! while (ptgt != NULL) {
mdb_printf("\n");
mdb_printf("devhdl %x, sasaddress %"PRIx64", phymask %x,"
! "devinfo %x\n", ptgt->m_devhdl, ptgt->m_sas_wwn,
! ptgt->m_phymask, ptgt->m_deviceinfo);
! mdb_printf("throttle %x, dr_flag %x, m_t_ncmds %x\n",
! ptgt->m_t_throttle, ptgt->m_dr_flag, ptgt->m_t_ncmds);
!
! mdb_free(ptgt, sizeof (mptsas_target_t));
! ptgt = (mptsas_target_t *)hash_traverse(
! &s->m_tgttbl, MPTSAS_HASH_NEXT, sizeof (mptsas_target_t));
}
mdb_printf("\n");
mdb_printf("The smp child information\n");
! psmp = (mptsas_smp_t *)hash_traverse(&s->m_smptbl,
! MPTSAS_HASH_FIRST, sizeof (mptsas_smp_t));
! while (psmp != NULL) {
mdb_printf("\n");
mdb_printf("devhdl %x, sasaddress %"PRIx64", phymask %x \n",
! psmp->m_devhdl, psmp->m_sasaddr, psmp->m_phymask);
!
! mdb_free(psmp, sizeof (mptsas_smp_t));
! psmp = (mptsas_smp_t *)hash_traverse(
! &s->m_smptbl, MPTSAS_HASH_NEXT, sizeof (mptsas_smp_t));
}
mdb_printf("\n");
#if 0
mdb_printf("targ wwn ncmds throttle "
"dr_flag timeout dups\n");
mdb_printf("-------------------------------"
"--------------------------------\n");
for (i = 0; i < MPTSAS_MAX_TARGETS; i++) {
! if (s->m_target[i].m_sas_wwn || s->m_target[i].m_deviceinfo) {
mdb_printf("%4d ", i);
! if (s->m_target[i].m_sas_wwn)
mdb_printf("%"PRIx64" ",
! s->m_target[i].m_sas_wwn);
mdb_printf("%3d", s->m_target[i].m_t_ncmds);
switch (s->m_target[i].m_t_throttle) {
case QFULL_THROTTLE:
mdb_printf(" QFULL ");
break;
--- 203,352 ----
mdb_printf("]\n");
}
void
! display_ports(struct mptsas *mp)
{
int i;
mdb_printf("\n");
mdb_printf("phy number and port mapping table\n");
for (i = 0; i < MPTSAS_MAX_PHYS; i++) {
! if (mp->m_phy_info[i].attached_devhdl) {
mdb_printf("phy %x --> port %x, phymask %x,"
! "attached_devhdl %x\n", i, mp->m_phy_info[i].port_num,
! mp->m_phy_info[i].phy_mask,
! mp->m_phy_info[i].attached_devhdl);
}
}
mdb_printf("\n");
}
!
! static uintptr_t
! klist_head(list_t *lp, uintptr_t klp)
{
! if ((uintptr_t)lp->list_head.list_next ==
! klp + offsetof(struct list, list_head))
! return (NULL);
! return ((uintptr_t)(((char *)lp->list_head.list_next) -
! lp->list_offset));
! }
!
! static uintptr_t
! klist_next(list_t *lp, uintptr_t klp, void *op)
! {
! /* LINTED E_BAD_PTR_CAST_ALIG */
! struct list_node *np = (struct list_node *)(((char *)op) +
! lp->list_offset);
!
! if ((uintptr_t)np->list_next == klp + offsetof(struct list, list_head))
return (NULL);
! return (((uintptr_t)(np->list_next)) - lp->list_offset);
! }
!
! static void *
! krefhash_first(uintptr_t khp)
! {
! refhash_t mh;
! uintptr_t klp;
! uintptr_t kop;
! void *rp;
!
! mdb_vread(&mh, sizeof (mh), khp);
! klp = klist_head(&mh.rh_objs, khp + offsetof(refhash_t, rh_objs));
! if (klp == 0)
return (NULL);
!
! kop = klp - mh.rh_link_off;
! rp = mdb_alloc(mh.rh_obj_size, UM_SLEEP);
! mdb_vread(rp, mh.rh_obj_size, kop);
!
! return (rp);
! }
!
! static void *
! krefhash_next(uintptr_t khp, void *op)
! {
! refhash_t mh;
! void *prev = op;
! refhash_link_t *lp;
! uintptr_t klp;
! uintptr_t kop;
! refhash_link_t ml;
! void *rp;
!
! mdb_vread(&mh, sizeof (mh), khp);
! /* LINTED E_BAD_PTR_CAST_ALIG */
! lp = (refhash_link_t *)(((char *)(op)) + mh.rh_link_off);
! ml = *lp;
! while ((klp = klist_next(&mh.rh_objs,
! khp + offsetof(refhash_t, rh_objs), &ml)) != NULL) {
! mdb_vread(&ml, sizeof (ml), klp);
! if (!(ml.rhl_flags & RHL_F_DEAD))
! break;
}
! if (klp == 0) {
! mdb_free(prev, mh.rh_obj_size);
return (NULL);
}
!
! kop = klp - mh.rh_link_off;
! rp = mdb_alloc(mh.rh_obj_size, UM_SLEEP);
! mdb_vread(rp, mh.rh_obj_size, kop);
!
! mdb_free(prev, mh.rh_obj_size);
! return (rp);
}
+
void
! display_targets(struct mptsas *mp)
{
mptsas_target_t *ptgt;
mptsas_smp_t *psmp;
mdb_printf("\n");
mdb_printf("The SCSI target information\n");
! for (ptgt = (mptsas_target_t *)krefhash_first((uintptr_t)mp->m_targets);
! ptgt != NULL;
! ptgt = krefhash_next((uintptr_t)mp->m_targets, ptgt)) {
mdb_printf("\n");
mdb_printf("devhdl %x, sasaddress %"PRIx64", phymask %x,"
! "devinfo %x\n", ptgt->m_devhdl, ptgt->m_addr.mta_wwn,
! ptgt->m_addr.mta_phymask, ptgt->m_deviceinfo);
! mdb_printf("throttle %x, dr_flag %x, m_t_ncmds %x, "
! "enclosure %x, slot_num %x\n", ptgt->m_t_throttle,
! ptgt->m_dr_flag, ptgt->m_t_ncmds, ptgt->m_enclosure,
! ptgt->m_slot_num);
}
+
mdb_printf("\n");
mdb_printf("The smp child information\n");
! for (psmp = (mptsas_smp_t *)krefhash_first(
! (uintptr_t)mp->m_smp_targets);
! psmp != NULL;
! psmp = krefhash_next((uintptr_t)mp->m_smp_targets, psmp)) {
mdb_printf("\n");
mdb_printf("devhdl %x, sasaddress %"PRIx64", phymask %x \n",
! psmp->m_devhdl, psmp->m_addr.mta_wwn,
! psmp->m_addr.mta_phymask);
}
mdb_printf("\n");
#if 0
mdb_printf("targ wwn ncmds throttle "
"dr_flag timeout dups\n");
mdb_printf("-------------------------------"
"--------------------------------\n");
for (i = 0; i < MPTSAS_MAX_TARGETS; i++) {
! if (s->m_target[i].m_addr.mta_wwn ||
! s->m_target[i].m_deviceinfo) {
mdb_printf("%4d ", i);
! if (s->m_target[i].m_addr.mta_wwn)
mdb_printf("%"PRIx64" ",
! s->m_target[i].m_addr.mta_wwn);
mdb_printf("%3d", s->m_target[i].m_t_ncmds);
switch (s->m_target[i].m_t_throttle) {
case QFULL_THROTTLE:
mdb_printf(" QFULL ");
break;
*** 425,435 ****
int mismatch = 0;
int wq, dq;
int ncmds = 0;
ulong_t saved_indent;
! nslots = s->m_n_slots;
slots = mdb_alloc(sizeof (mptsas_cmd_t) * nslots, UM_SLEEP);
for (i = 0; i < nslots; i++)
if (s->m_slot[i]) {
--- 452,462 ----
int mismatch = 0;
int wq, dq;
int ncmds = 0;
ulong_t saved_indent;
! nslots = s->m_n_normal;
slots = mdb_alloc(sizeof (mptsas_cmd_t) * nslots, UM_SLEEP);
for (i = 0; i < nslots; i++)
if (s->m_slot[i]) {
*** 478,488 ****
mdb_printf("%3d %2d %2d\n", tcmds, wq, dq);
saved_indent = mdb_dec_indent(0);
mdb_dec_indent(saved_indent);
! for (i = 0; i < s->m_n_slots; i++)
if (s->m_slot[i]) {
if (!header_output) {
mdb_printf("\n");
mdb_printf("mptsas_cmd slot cmd_slot "
"cmd_flags cmd_pkt_flags scsi_pkt "
--- 505,515 ----
mdb_printf("%3d %2d %2d\n", tcmds, wq, dq);
saved_indent = mdb_dec_indent(0);
mdb_dec_indent(saved_indent);
! for (i = 0; i < s->m_n_normal; i++)
if (s->m_slot[i]) {
if (!header_output) {
mdb_printf("\n");
mdb_printf("mptsas_cmd slot cmd_slot "
"cmd_flags cmd_pkt_flags scsi_pkt "
*** 600,615 ****
mdb_printf("The slot information is not implemented yet\n");
return (0);
}
void
! display_deviceinfo(struct mptsas m)
{
char device_path[PATH_MAX];
*device_path = 0;
! if (construct_path((uintptr_t)m.m_dip, device_path) != DCMD_OK) {
strcpy(device_path, "couldn't determine device path");
}
mdb_printf("\n");
mdb_printf("Path in device tree %s\n", device_path);
--- 627,642 ----
mdb_printf("The slot information is not implemented yet\n");
return (0);
}
void
! display_deviceinfo(struct mptsas *mp)
{
char device_path[PATH_MAX];
*device_path = 0;
! if (construct_path((uintptr_t)mp->m_dip, device_path) != DCMD_OK) {
strcpy(device_path, "couldn't determine device path");
}
mdb_printf("\n");
mdb_printf("Path in device tree %s\n", device_path);
*** 741,751 ****
m.m_active);
mdb_free(s, sizeof (mptsas_slots_t));
return (DCMD_ERR);
}
! nslots = s->m_n_slots;
mdb_free(s, sizeof (mptsas_slots_t));
slot_size = sizeof (mptsas_slots_t) +
(sizeof (mptsas_cmd_t *) * (nslots-1));
--- 768,778 ----
m.m_active);
mdb_free(s, sizeof (mptsas_slots_t));
return (DCMD_ERR);
}
! nslots = s->m_n_normal;
mdb_free(s, sizeof (mptsas_slots_t));
slot_size = sizeof (mptsas_slots_t) +
(sizeof (mptsas_cmd_t *) * (nslots-1));
*** 794,810 ****
mdb_printf("\n");
mdb_inc_indent(17);
if (target_info)
! display_targets(s);
if (port_info)
! display_ports(m);
if (device_info)
! display_deviceinfo(m);
if (slot_info)
display_slotinfo();
mdb_dec_indent(17);
--- 821,837 ----
mdb_printf("\n");
mdb_inc_indent(17);
if (target_info)
! display_targets(&m);
if (port_info)
! display_ports(&m);
if (device_info)
! display_deviceinfo(&m);
if (slot_info)
display_slotinfo();
mdb_dec_indent(17);
*** 811,823 ****
mdb_free(s, slot_size);
return (rv);
}
! /*
! * Only -t is implemented now, will add more later when the driver is stable
! */
void
mptsas_help()
{
mdb_printf("Prints summary information about each mpt_sas instance, "
"including warning\nmessages when slot usage doesn't match "
--- 838,848 ----
mdb_free(s, slot_size);
return (rv);
}
!
void
mptsas_help()
{
mdb_printf("Prints summary information about each mpt_sas instance, "
"including warning\nmessages when slot usage doesn't match "