Print this page
4682 panic in mptsas refhash
Reviewed by: Dan McDonald <danmcd@omniti.com>
Reviewed by: Hans Rosenfeld <hans.rosenfeld@nexenta.com>
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
Approved by: Albert Lee <trisk@nexenta.com>
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>

@@ -20,11 +20,11 @@
  */
 
 /*
  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
- * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2014, Joyent, Inc. All rights reserved.
  * Copyright 2014 OmniTI Computer Consulting, Inc. All rights reserved.
  */
 
 /*
  * Copyright (c) 2000 to 2010, LSI Corporation.

@@ -95,10 +95,11 @@
  */
 #include <sys/scsi/impl/scsi_reset_notify.h>
 #include <sys/scsi/adapters/mpt_sas/mptsas_var.h>
 #include <sys/scsi/adapters/mpt_sas/mptsas_ioctl.h>
 #include <sys/scsi/adapters/mpt_sas/mptsas_smhba.h>
+#include <sys/scsi/adapters/mpt_sas/mptsas_hash.h>
 #include <sys/raidioctl.h>
 
 #include <sys/fs/dv_node.h>     /* devfs_clean */
 
 /*

@@ -334,16 +335,16 @@
 
 static int mptsas_parse_address(char *name, uint64_t *wwid, uint8_t *phy,
     int *lun);
 static int mptsas_parse_smp_name(char *name, uint64_t *wwn);
 
-static mptsas_target_t *mptsas_phy_to_tgt(mptsas_t *mpt, int phymask,
-    uint8_t phy);
-static mptsas_target_t *mptsas_wwid_to_ptgt(mptsas_t *mpt, int phymask,
-    uint64_t wwid);
-static mptsas_smp_t *mptsas_wwid_to_psmp(mptsas_t *mpt, int phymask,
-    uint64_t wwid);
+static mptsas_target_t *mptsas_phy_to_tgt(mptsas_t *mpt,
+    mptsas_phymask_t phymask, uint8_t phy);
+static mptsas_target_t *mptsas_wwid_to_ptgt(mptsas_t *mpt,
+    mptsas_phymask_t phymask, uint64_t wwid);
+static mptsas_smp_t *mptsas_wwid_to_psmp(mptsas_t *mpt,
+    mptsas_phymask_t phymask, uint64_t wwid);
 
 static int mptsas_inquiry(mptsas_t *mpt, mptsas_target_t *ptgt, int lun,
     uchar_t page, unsigned char *buf, int len, int *rlen, uchar_t evpd);
 
 static int mptsas_get_target_device_info(mptsas_t *mpt, uint32_t page_address,

@@ -405,27 +406,13 @@
     int mode, int *rval);
 static void mptsas_record_event(void *args);
 static int mptsas_reg_access(mptsas_t *mpt, mptsas_reg_access_t *data,
     int mode);
 
-static void mptsas_hash_init(mptsas_hash_table_t *hashtab);
-static void mptsas_hash_uninit(mptsas_hash_table_t *hashtab, size_t datalen);
-static void mptsas_hash_add(mptsas_hash_table_t *hashtab, void *data);
-static void * mptsas_hash_rem(mptsas_hash_table_t *hashtab, uint64_t key1,
-    mptsas_phymask_t key2);
-static void * mptsas_hash_search(mptsas_hash_table_t *hashtab, uint64_t key1,
-    mptsas_phymask_t key2);
-static void * mptsas_hash_traverse(mptsas_hash_table_t *hashtab, int pos);
-
-mptsas_target_t *mptsas_tgt_alloc(mptsas_hash_table_t *, uint16_t, uint64_t,
+mptsas_target_t *mptsas_tgt_alloc(mptsas_t *, uint16_t, uint64_t,
     uint32_t, mptsas_phymask_t, uint8_t);
-static mptsas_smp_t *mptsas_smp_alloc(mptsas_hash_table_t *hashtab,
-    mptsas_smp_t *data);
-static void mptsas_smp_free(mptsas_hash_table_t *hashtab, uint64_t wwid,
-    mptsas_phymask_t phymask);
-static void mptsas_tgt_free(mptsas_hash_table_t *, uint64_t, mptsas_phymask_t);
-static void * mptsas_search_by_devhdl(mptsas_hash_table_t *, uint16_t);
+static mptsas_smp_t *mptsas_smp_alloc(mptsas_t *, mptsas_smp_t *);
 static int mptsas_online_smp(dev_info_t *pdip, mptsas_smp_t *smp_node,
     dev_info_t **smp_dip);
 
 /*
  * Power management functions

@@ -693,12 +680,107 @@
         NDBG0(("mptsas _info"));
 
         return (mod_info(&modlinkage, modinfop));
 }
 
+static int
+mptsas_target_eval_devhdl(const void *op, void *arg)
+{
+        uint16_t dh = *(uint16_t *)arg;
+        const mptsas_target_t *tp = op;
 
+        return ((int)tp->m_devhdl - (int)dh);
+}
+
 static int
+mptsas_target_eval_slot(const void *op, void *arg)
+{
+        mptsas_led_control_t *lcp = arg;
+        const mptsas_target_t *tp = op;
+
+        if (tp->m_enclosure != lcp->Enclosure)
+                return ((int)tp->m_enclosure - (int)lcp->Enclosure);
+
+        return ((int)tp->m_slot_num - (int)lcp->Slot);
+}
+
+static int
+mptsas_target_eval_nowwn(const void *op, void *arg)
+{
+        uint8_t phy = *(uint8_t *)arg;
+        const mptsas_target_t *tp = op;
+
+        if (tp->m_addr.mta_wwn != 0)
+                return (-1);
+
+        return ((int)tp->m_phynum - (int)phy);
+}
+
+static int
+mptsas_smp_eval_devhdl(const void *op, void *arg)
+{
+        uint16_t dh = *(uint16_t *)arg;
+        const mptsas_smp_t *sp = op;
+
+        return ((int)sp->m_devhdl - (int)dh);
+}
+
+static uint64_t
+mptsas_target_addr_hash(const void *tp)
+{
+        const mptsas_target_addr_t *tap = tp;
+
+        return ((tap->mta_wwn & 0xffffffffffffULL) |
+            ((uint64_t)tap->mta_phymask << 48));
+}
+
+static int
+mptsas_target_addr_cmp(const void *a, const void *b)
+{
+        const mptsas_target_addr_t *aap = a;
+        const mptsas_target_addr_t *bap = b;
+
+        if (aap->mta_wwn < bap->mta_wwn)
+                return (-1);
+        if (aap->mta_wwn > bap->mta_wwn)
+                return (1);
+        return ((int)bap->mta_phymask - (int)aap->mta_phymask);
+}
+
+static void
+mptsas_target_free(void *op)
+{
+        kmem_free(op, sizeof (mptsas_target_t));
+}
+
+static void
+mptsas_smp_free(void *op)
+{
+        kmem_free(op, sizeof (mptsas_smp_t));
+}
+
+static void
+mptsas_destroy_hashes(mptsas_t *mpt)
+{
+        mptsas_target_t *tp;
+        mptsas_smp_t *sp;
+
+        for (tp = refhash_first(mpt->m_targets); tp != NULL;
+            tp = refhash_next(mpt->m_targets, tp)) {
+                refhash_remove(mpt->m_targets, tp);
+        }
+        for (sp = refhash_first(mpt->m_smp_targets); sp != NULL;
+            sp = refhash_next(mpt->m_smp_targets, sp)) {
+                refhash_remove(mpt->m_smp_targets, sp);
+        }
+        refhash_destroy(mpt->m_targets);
+        refhash_destroy(mpt->m_smp_targets);
+        mpt->m_targets = NULL;
+        mpt->m_smp_targets = NULL;
+}
+
+static int
 mptsas_iport_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 {
         dev_info_t              *pdip;
         mptsas_t                *mpt;
         scsi_hba_tran_t         *hba_tran;

@@ -1402,15 +1484,16 @@
                 }
                 if (hba_attach_setup) {
                         mptsas_hba_teardown(mpt);
                 }
 
+                if (mpt->m_targets)
+                        refhash_destroy(mpt->m_targets);
+                if (mpt->m_smp_targets)
+                        refhash_destroy(mpt->m_smp_targets);
+
                 if (mpt->m_active) {
-                        mptsas_hash_uninit(&mpt->m_active->m_smptbl,
-                            sizeof (mptsas_smp_t));
-                        mptsas_hash_uninit(&mpt->m_active->m_tgttbl,
-                            sizeof (mptsas_target_t));
                         mptsas_free_active_slots(mpt);
                 }
                 if (intr_added) {
                         mptsas_unregister_intrs(mpt);
                 }

@@ -1839,16 +1922,16 @@
         /*
          * Delete Phy stats
          */
         mptsas_destroy_phy_stats(mpt);
 
+        mptsas_destroy_hashes(mpt);
+
         /*
          * Delete nt_active.
          */
         mutex_enter(&mpt->m_mutex);
-        mptsas_hash_uninit(&mpt->m_active->m_tgttbl, sizeof (mptsas_target_t));
-        mptsas_hash_uninit(&mpt->m_active->m_smptbl, sizeof (mptsas_smp_t));
         mptsas_free_active_slots(mpt);
         mutex_exit(&mpt->m_mutex);
 
         /* deallocate everything that was allocated in mptsas_attach */
         mptsas_cache_destroy(mpt);

@@ -2105,11 +2188,15 @@
                 return (FALSE);
         }
         /*
          * Initialize smp hash table
          */
-        mptsas_hash_init(&mpt->m_active->m_smptbl);
+        mpt->m_smp_targets = refhash_create(MPTSAS_SMP_BUCKET_COUNT,
+            mptsas_target_addr_hash, mptsas_target_addr_cmp,
+            mptsas_smp_free, sizeof (mptsas_smp_t),
+            offsetof(mptsas_smp_t, m_link), offsetof(mptsas_smp_t, m_addr),
+            KM_SLEEP);
         mpt->m_smp_devhdl = 0xFFFF;
 
         return (TRUE);
 }
 

@@ -2748,12 +2835,13 @@
         int                     lun = sd->sd_address.a_lun;
         mdi_pathinfo_t          *pip = NULL;
         mptsas_tgt_private_t    *tgt_private = NULL;
         mptsas_target_t         *ptgt = NULL;
         char                    *psas_wwn = NULL;
-        int                     phymask = 0;
+        mptsas_phymask_t        phymask = 0;
         uint64_t                sas_wwn = 0;
+        mptsas_target_addr_t    addr;
         mpt = SDEV2MPT(sd);
 
         ASSERT(scsi_hba_iport_unit_address(hba_dip) != 0);
 
         NDBG0(("mptsas_scsi_tgt_init: hbadip=0x%p tgtdip=0x%p lun=%d",

@@ -2765,11 +2853,11 @@
                 return (DDI_FAILURE);
         }
         /*
          * phymask is 0 means the virtual port for RAID
          */
-        phymask = ddi_prop_get_int(DDI_DEV_T_ANY, hba_dip, 0,
+        phymask = (mptsas_phymask_t)ddi_prop_get_int(DDI_DEV_T_ANY, hba_dip, 0,
             "phymask", 0);
         if (mdi_component_is_client(tgt_dip, NULL) == MDI_SUCCESS) {
                 if ((pip = (void *)(sd->sd_private)) == NULL) {
                         /*
                          * Very bad news if this occurs. Somehow scsi_vhci has

@@ -2803,13 +2891,16 @@
                         ddi_prop_free(psas_wwn);
                 } else {
                         sas_wwn = 0;
                 }
         }
+
         ASSERT((sas_wwn != 0) || (phymask != 0));
+        addr.mta_wwn = sas_wwn;
+        addr.mta_phymask = phymask;
         mutex_enter(&mpt->m_mutex);
-        ptgt = mptsas_hash_search(&mpt->m_active->m_tgttbl, sas_wwn, phymask);
+        ptgt = refhash_lookup(mpt->m_targets, &addr);
         mutex_exit(&mpt->m_mutex);
         if (ptgt == NULL) {
                 mptsas_log(mpt, CE_WARN, "!tgt_init: target doesn't exist or "
                     "gone already! phymask:%x, saswwn %"PRIx64, phymask,
                     sas_wwn);

@@ -3236,41 +3327,44 @@
 }
 
 int
 mptsas_save_cmd(mptsas_t *mpt, mptsas_cmd_t *cmd)
 {
-        mptsas_slots_t  *slots;
-        int             slot;
+        mptsas_slots_t *slots = mpt->m_active;
+        uint_t slot, start_rotor;
         mptsas_target_t *ptgt = cmd->cmd_tgt_addr;
 
-        ASSERT(mutex_owned(&mpt->m_mutex));
-        slots = mpt->m_active;
+        ASSERT(MUTEX_HELD(&mpt->m_mutex));
 
         /*
          * Account for reserved TM request slot and reserved SMID of 0.
          */
-        ASSERT(slots->m_n_slots == (mpt->m_max_requests - 2));
+        ASSERT(slots->m_n_normal == (mpt->m_max_requests - 2));
 
         /*
-         * m_tags is equivalent to the SMID when sending requests.  Since the
-         * SMID cannot be 0, start out at one if rolling over past the size
-         * of the request queue depth.  Also, don't use the last SMID, which is
-         * reserved for TM requests.
+         * Find the next available slot, beginning at m_rotor.  If no slot is
+         * available, we'll return FALSE to indicate that.  This mechanism
+         * considers only the normal slots, not the reserved slot 0 nor the
+         * task management slot m_n_normal + 1.  The rotor is left to point to
+         * the normal slot after the one we select, unless we select the last
+         * normal slot in which case it returns to slot 1.
          */
-        slot = (slots->m_tags)++;
-        if (slots->m_tags > slots->m_n_slots) {
-                slots->m_tags = 1;
-        }
+        start_rotor = slots->m_rotor;
+        do {
+                slot = slots->m_rotor++;
+                if (slots->m_rotor > slots->m_n_normal)
+                        slots->m_rotor = 1;
 
-alloc_tag:
-        /* Validate tag, should never fail. */
-        if (slots->m_slot[slot] == NULL) {
-                /*
-                 * Make sure SMID is not using reserved value of 0
-                 * and the TM request slot.
-                 */
-                ASSERT((slot > 0) && (slot <= slots->m_n_slots));
+                if (slots->m_rotor == start_rotor)
+                        break;
+        } while (slots->m_slot[slot] != NULL);
+
+        if (slots->m_slot[slot] != NULL)
+                return (FALSE);
+
+        ASSERT(slot != 0 && slot <= slots->m_n_normal);
+
                 cmd->cmd_slot = slot;
                 slots->m_slot[slot] = cmd;
                 mpt->m_ncmds++;
 
                 /*

@@ -3290,29 +3384,10 @@
                  */
                 if (cmd->cmd_active_timeout <= mptsas_scsi_watchdog_tick) {
                         cmd->cmd_active_timeout += mptsas_scsi_watchdog_tick;
                 }
                 return (TRUE);
-        } else {
-                int i;
-
-                /*
-                 * If slot in use, scan until a free one is found. Don't use 0
-                 * or final slot, which is reserved for TM requests.
-                 */
-                for (i = 0; i < slots->m_n_slots; i++) {
-                        slot = slots->m_tags;
-                        if (++(slots->m_tags) > slots->m_n_slots) {
-                                slots->m_tags = 1;
-                        }
-                        if (slots->m_slot[slot] == NULL) {
-                                NDBG22(("found free slot %d", slot));
-                                goto alloc_tag;
-                        }
-                }
-        }
-        return (FALSE);
 }
 
 /*
  * prepare the pkt:
  * the pkt may have been resubmitted or just reused so

@@ -4649,11 +4724,11 @@
         /*
          * This is a success reply so just complete the IO.  First, do a sanity
          * check on the SMID.  The final slot is used for TM requests, which
          * would not come into this reply handler.
          */
-        if ((SMID == 0) || (SMID > slots->m_n_slots)) {
+        if ((SMID == 0) || (SMID > slots->m_n_normal)) {
                 mptsas_log(mpt, CE_WARN, "?Received invalid SMID of %d\n",
                     SMID);
                 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
                 return;
         }

@@ -4752,11 +4827,11 @@
             (function != MPI2_FUNCTION_DIAG_BUFFER_POST)) {
                 /*
                  * This could be a TM reply, which use the last allocated SMID,
                  * so allow for that.
                  */
-                if ((SMID == 0) || (SMID > (slots->m_n_slots + 1))) {
+                if ((SMID == 0) || (SMID > (slots->m_n_normal + 1))) {
                         mptsas_log(mpt, CE_WARN, "?Received invalid SMID of "
                             "%d\n", SMID);
                         ddi_fm_service_impact(mpt->m_dip,
                             DDI_SERVICE_UNAFFECTED);
                         return;

@@ -5069,11 +5144,11 @@
                                     "reconfigure.\n");
                                 break;
                         }
                         topo_node->mpt = mpt;
                         topo_node->event = MPTSAS_DR_EVENT_RECONFIG_TARGET;
-                        topo_node->un.phymask = ptgt->m_phymask;
+                        topo_node->un.phymask = ptgt->m_addr.mta_phymask;
                         topo_node->devhdl = ptgt->m_devhdl;
                         topo_node->object = (void *)ptgt;
                         topo_node->flags = MPTSAS_TOPO_FLAG_LUN_ASSOCIATED;
 
                         if ((ddi_taskq_dispatch(mpt->m_dr_taskq,

@@ -5135,17 +5210,13 @@
                 case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES:
                 case MPI2_IOCSTATUS_BUSY:
                         /*
                          * set throttles to drain
                          */
-                        ptgt = (mptsas_target_t *)mptsas_hash_traverse(
-                            &mpt->m_active->m_tgttbl, MPTSAS_HASH_FIRST);
-                        while (ptgt != NULL) {
+                        for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL;
+                            ptgt = refhash_next(mpt->m_targets, ptgt)) {
                                 mptsas_set_throttle(mpt, ptgt, DRAIN_THROTTLE);
-
-                                ptgt = (mptsas_target_t *)mptsas_hash_traverse(
-                                    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
                         }
 
                         /*
                          * retry command
                          */

@@ -5832,12 +5903,12 @@
                 if (topo_node->flags == MPTSAS_TOPO_FLAG_RAID_ASSOCIATED) {
                         /*
                          * Get latest RAID info.
                          */
                         (void) mptsas_get_raid_info(mpt);
-                        ptgt = mptsas_search_by_devhdl(
-                            &mpt->m_active->m_tgttbl, topo_node->devhdl);
+                        ptgt = refhash_linear_search(mpt->m_targets,
+                            mptsas_target_eval_devhdl, &topo_node->devhdl);
                         if (ptgt == NULL)
                                 break;
                 } else {
                         ptgt = (void *)topo_node->object;
                 }

@@ -5882,11 +5953,11 @@
 
                 mutex_exit(&mpt->m_mutex);
                 flags = topo_node->flags;
 
                 if (flags == MPTSAS_TOPO_FLAG_RAID_PHYSDRV_ASSOCIATED) {
-                        phymask = ptgt->m_phymask;
+                        phymask = ptgt->m_addr.mta_phymask;
                         phy_mask_name = kmem_zalloc(MPTSAS_MAX_PHYS, KM_SLEEP);
                         (void) sprintf(phy_mask_name, "%x", phymask);
                         parent = scsi_hba_iport_find(mpt->m_dip,
                             phy_mask_name);
                         kmem_free(phy_mask_name, MPTSAS_MAX_PHYS);

@@ -5921,11 +5992,11 @@
                          */
                         if (flags == MPTSAS_TOPO_FLAG_DIRECT_ATTACHED_DEVICE) {
                                 bzero(attached_wwnstr,
                                     sizeof (attached_wwnstr));
                                 (void) sprintf(attached_wwnstr, "w%016"PRIx64,
-                                    ptgt->m_sas_wwn);
+                                    ptgt->m_addr.mta_wwn);
                                 if (ddi_prop_update_string(DDI_DEV_T_NONE,
                                     parent,
                                     SCSI_ADDR_PROP_ATTACHED_PORT,
                                     attached_wwnstr)
                                     != DDI_PROP_SUCCESS) {

@@ -5979,22 +6050,22 @@
                 }
                 mutex_enter(&mpt->m_mutex);
 
                 NDBG20(("mptsas%d handle_topo_change to online devhdl:%x, "
                     "phymask:%x.", mpt->m_instance, ptgt->m_devhdl,
-                    ptgt->m_phymask));
+                    ptgt->m_addr.mta_phymask));
                 break;
         }
         case MPTSAS_DR_EVENT_OFFLINE_TARGET:
         {
-                mptsas_hash_table_t *tgttbl = &mpt->m_active->m_tgttbl;
                 devhdl = topo_node->devhdl;
-                ptgt = mptsas_search_by_devhdl(tgttbl, devhdl);
+                ptgt = refhash_linear_search(mpt->m_targets,
+                    mptsas_target_eval_devhdl, &devhdl);
                 if (ptgt == NULL)
                         break;
 
-                sas_wwn = ptgt->m_sas_wwn;
+                sas_wwn = ptgt->m_addr.mta_wwn;
                 phy = ptgt->m_phynum;
 
                 addr = kmem_zalloc(SCSI_MAXNAMELEN, KM_SLEEP);
 
                 if (sas_wwn) {

@@ -6018,12 +6089,12 @@
                  */
                 rval = mptsas_do_scsi_reset(mpt, devhdl);
                 if (rval) {
                         NDBG20(("mptsas%d handle_topo_change to reset target "
                             "before offline devhdl:%x, phymask:%x, rval:%x",
-                            mpt->m_instance, ptgt->m_devhdl, ptgt->m_phymask,
-                            rval));
+                            mpt->m_instance, ptgt->m_devhdl,
+                            ptgt->m_addr.mta_phymask, rval));
                 }
 
                 mutex_exit(&mpt->m_mutex);
 
                 ndi_devi_enter(scsi_vhci_dip, &circ);

@@ -6031,11 +6102,11 @@
                 rval = mptsas_offline_target(parent, addr);
                 ndi_devi_exit(parent, circ1);
                 ndi_devi_exit(scsi_vhci_dip, circ);
                 NDBG20(("mptsas%d handle_topo_change to offline devhdl:%x, "
                     "phymask:%x, rval:%x", mpt->m_instance,
-                    ptgt->m_devhdl, ptgt->m_phymask, rval));
+                    ptgt->m_devhdl, ptgt->m_addr.mta_phymask, rval));
 
                 kmem_free(addr, SCSI_MAXNAMELEN);
 
                 /*
                  * Clear parent's props for SMHBA support

@@ -6074,12 +6145,11 @@
 
                 mutex_enter(&mpt->m_mutex);
                 ptgt->m_led_status = 0;
                 (void) mptsas_flush_led_status(mpt, ptgt);
                 if (rval == DDI_SUCCESS) {
-                        mptsas_tgt_free(&mpt->m_active->m_tgttbl,
-                            ptgt->m_sas_wwn, ptgt->m_phymask);
+                        refhash_remove(mpt->m_targets, ptgt);
                         ptgt = NULL;
                 } else {
                         /*
                          * clean DR_INTRANSITION flag to allow I/O down to
                          * PHCI driver since failover finished.

@@ -6132,11 +6202,10 @@
         }
         case MPTSAS_DR_EVENT_RECONFIG_SMP:
         {
                 mptsas_smp_t smp;
                 dev_info_t *smpdip;
-                mptsas_hash_table_t *smptbl = &mpt->m_active->m_smptbl;
 
                 devhdl = topo_node->devhdl;
 
                 page_address = (MPI2_SAS_EXPAND_PGAD_FORM_HNDL &
                     MPI2_SAS_EXPAND_PGAD_FORM_MASK) | (uint32_t)devhdl;

@@ -6145,11 +6214,11 @@
                         mptsas_log(mpt, CE_WARN, "failed to online smp, "
                             "handle %x", devhdl);
                         return;
                 }
 
-                psmp = mptsas_smp_alloc(smptbl, &smp);
+                psmp = mptsas_smp_alloc(mpt, &smp);
                 if (psmp == NULL) {
                         return;
                 }
 
                 mutex_exit(&mpt->m_mutex);

@@ -6160,15 +6229,15 @@
                 mutex_enter(&mpt->m_mutex);
                 break;
         }
         case MPTSAS_DR_EVENT_OFFLINE_SMP:
         {
-                mptsas_hash_table_t *smptbl = &mpt->m_active->m_smptbl;
                 devhdl = topo_node->devhdl;
                 uint32_t dev_info;
 
-                psmp = mptsas_search_by_devhdl(smptbl, devhdl);
+                psmp = refhash_linear_search(mpt->m_smp_targets,
+                    mptsas_smp_eval_devhdl, &devhdl);
                 if (psmp == NULL)
                         break;
                 /*
                  * The mptsas_smp_t data is released only if the dip is offlined
                  * successfully.

@@ -6220,12 +6289,11 @@
 
                 mutex_enter(&mpt->m_mutex);
                 NDBG20(("mptsas%d handle_topo_change to remove devhdl:%x, "
                     "rval:%x", mpt->m_instance, psmp->m_devhdl, rval));
                 if (rval == DDI_SUCCESS) {
-                        mptsas_smp_free(smptbl, psmp->m_sasaddr,
-                            psmp->m_phymask);
+                        refhash_remove(mpt->m_smp_targets, psmp);
                 } else {
                         psmp->m_devhdl = MPTSAS_INVALID_DEVHDL;
                 }
 
                 bzero(attached_wwnstr, sizeof (attached_wwnstr));

@@ -6380,19 +6448,15 @@
                 mptsas_topo_change_list_t       *topo_head = NULL;
                 mptsas_topo_change_list_t       *topo_tail = NULL;
                 mptsas_topo_change_list_t       *topo_node = NULL;
                 mptsas_target_t                 *ptgt;
                 mptsas_smp_t                    *psmp;
-                mptsas_hash_table_t             *tgttbl, *smptbl;
                 uint8_t                         flags = 0, exp_flag;
                 smhba_info_t                    *pSmhba = NULL;
 
                 NDBG20(("mptsas_handle_event_sync: SAS topology change"));
 
-                tgttbl = &mpt->m_active->m_tgttbl;
-                smptbl = &mpt->m_active->m_smptbl;
-
                 sas_topo_change_list = (pMpi2EventDataSasTopologyChangeList_t)
                     eventreply->EventData;
 
                 enc_handle = ddi_get16(mpt->m_acc_reply_frame_hdl,
                     &sas_topo_change_list->EnclosureHandle);

@@ -6434,20 +6498,21 @@
                                 }
                                 break;
                         case MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING:
                                 (void) sprintf(string, " not responding, "
                                     "removed");
-                                psmp = mptsas_search_by_devhdl(smptbl,
-                                    expd_handle);
+                                psmp = refhash_linear_search(mpt->m_smp_targets,
+                                    mptsas_smp_eval_devhdl, &expd_handle);
                                 if (psmp == NULL)
                                         break;
 
                                 topo_node = kmem_zalloc(
                                     sizeof (mptsas_topo_change_list_t),
                                     KM_SLEEP);
                                 topo_node->mpt = mpt;
-                                topo_node->un.phymask = psmp->m_phymask;
+                                topo_node->un.phymask =
+                                    psmp->m_addr.mta_phymask;
                                 topo_node->event = MPTSAS_DR_EVENT_OFFLINE_SMP;
                                 topo_node->devhdl = expd_handle;
                                 topo_node->flags = flags;
                                 topo_node->object = NULL;
                                 if (topo_head == NULL) {

@@ -6594,12 +6659,12 @@
                                 /*
                                  * Target device is removed from the system
                                  * Before the device is really offline from
                                  * from system.
                                  */
-                                ptgt = mptsas_search_by_devhdl(tgttbl,
-                                    dev_handle);
+                                ptgt = refhash_linear_search(mpt->m_targets,
+                                    mptsas_target_eval_devhdl, &dev_handle);
                                 /*
                                  * If ptgt is NULL here, it means that the
                                  * DevHandle is not in the hash table.  This is
                                  * reasonable sometimes.  For example, if a
                                  * disk was pulled, then added, then pulled

@@ -6647,11 +6712,12 @@
 
                                 topo_node = kmem_zalloc(
                                     sizeof (mptsas_topo_change_list_t),
                                     KM_SLEEP);
                                 topo_node->mpt = mpt;
-                                topo_node->un.phymask = ptgt->m_phymask;
+                                topo_node->un.phymask =
+                                    ptgt->m_addr.mta_phymask;
                                 topo_node->event =
                                     MPTSAS_DR_EVENT_OFFLINE_TARGET;
                                 topo_node->devhdl = dev_handle;
                                 topo_node->flags = flags;
                                 topo_node->object = NULL;

@@ -6807,21 +6873,18 @@
                 Mpi2EventDataIrConfigChangeList_t       *irChangeList;
                 mptsas_topo_change_list_t               *topo_head = NULL;
                 mptsas_topo_change_list_t               *topo_tail = NULL;
                 mptsas_topo_change_list_t               *topo_node = NULL;
                 mptsas_target_t                         *ptgt;
-                mptsas_hash_table_t                     *tgttbl;
                 uint8_t                                 num_entries, i, reason;
                 uint16_t                                volhandle, diskhandle;
 
                 irChangeList = (pMpi2EventDataIrConfigChangeList_t)
                     eventreply->EventData;
                 num_entries = ddi_get8(mpt->m_acc_reply_frame_hdl,
                     &irChangeList->NumElements);
 
-                tgttbl = &mpt->m_active->m_tgttbl;
-
                 NDBG20(("mptsas%d IR_CONFIGURATION_CHANGE_LIST event received",
                     mpt->m_instance));
 
                 for (i = 0; i < num_entries; i++) {
                         reason = ddi_get8(mpt->m_acc_reply_frame_hdl,

@@ -6861,12 +6924,12 @@
                         case MPI2_EVENT_IR_CHANGE_RC_REMOVED:
                         case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED:
                         {
                                 NDBG20(("mptsas %d volume deleted\n",
                                     mpt->m_instance));
-                                ptgt = mptsas_search_by_devhdl(tgttbl,
-                                    volhandle);
+                                ptgt = refhash_linear_search(mpt->m_targets,
+                                    mptsas_target_eval_devhdl, &volhandle);
                                 if (ptgt == NULL)
                                         break;
 
                                 /*
                                  * Clear any flags related to volume

@@ -6882,11 +6945,12 @@
 
                                 topo_node = kmem_zalloc(
                                     sizeof (mptsas_topo_change_list_t),
                                     KM_SLEEP);
                                 topo_node->mpt = mpt;
-                                topo_node->un.phymask = ptgt->m_phymask;
+                                topo_node->un.phymask =
+                                    ptgt->m_addr.mta_phymask;
                                 topo_node->event =
                                     MPTSAS_DR_EVENT_OFFLINE_TARGET;
                                 topo_node->devhdl = volhandle;
                                 topo_node->flags =
                                     MPTSAS_TOPO_FLAG_RAID_ASSOCIATED;

@@ -6900,12 +6964,12 @@
                                 break;
                         }
                         case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
                         case MPI2_EVENT_IR_CHANGE_RC_HIDE:
                         {
-                                ptgt = mptsas_search_by_devhdl(tgttbl,
-                                    diskhandle);
+                                ptgt = refhash_linear_search(mpt->m_targets,
+                                    mptsas_target_eval_devhdl, &diskhandle);
                                 if (ptgt == NULL)
                                         break;
 
                                 /*
                                  * Update DR flag immediately avoid I/O failure

@@ -6916,11 +6980,12 @@
 
                                 topo_node = kmem_zalloc(
                                     sizeof (mptsas_topo_change_list_t),
                                     KM_SLEEP);
                                 topo_node->mpt = mpt;
-                                topo_node->un.phymask = ptgt->m_phymask;
+                                topo_node->un.phymask =
+                                    ptgt->m_addr.mta_phymask;
                                 topo_node->event =
                                     MPTSAS_DR_EVENT_OFFLINE_TARGET;
                                 topo_node->devhdl = diskhandle;
                                 topo_node->flags =
                                     MPTSAS_TOPO_FLAG_RAID_PHYSDRV_ASSOCIATED;

@@ -7341,11 +7406,10 @@
         {
                 Mpi2EventDataIrVolume_t         *irVolume;
                 uint16_t                        devhandle;
                 uint32_t                        state;
                 int                             config, vol;
-                mptsas_slots_t                  *slots = mpt->m_active;
                 uint8_t                         found = FALSE;
 
                 irVolume = (pMpi2EventDataIrVolume_t)eventreply->EventData;
                 state = ddi_get32(mpt->m_acc_reply_frame_hdl,
                     &irVolume->NewValue);

@@ -7358,14 +7422,14 @@
                  * Get latest RAID info and then find the DevHandle for this
                  * event in the configuration.  If the DevHandle is not found
                  * just exit the event.
                  */
                 (void) mptsas_get_raid_info(mpt);
-                for (config = 0; (config < slots->m_num_raid_configs) &&
+                for (config = 0; (config < mpt->m_num_raid_configs) &&
                     (!found); config++) {
                         for (vol = 0; vol < MPTSAS_MAX_RAIDVOLS; vol++) {
-                                if (slots->m_raidconfig[config].m_raidvol[vol].
+                                if (mpt->m_raidconfig[config].m_raidvol[vol].
                                     m_raidhandle == devhandle) {
                                         found = TRUE;
                                         break;
                                 }
                         }

@@ -7376,11 +7440,11 @@
 
                 switch (irVolume->ReasonCode) {
                 case MPI2_EVENT_IR_VOLUME_RC_SETTINGS_CHANGED:
                 {
                         uint32_t i;
-                        slots->m_raidconfig[config].m_raidvol[vol].m_settings =
+                        mpt->m_raidconfig[config].m_raidvol[vol].m_settings =
                             state;
 
                         i = state & MPI2_RAIDVOL0_SETTING_MASK_WRITE_CACHING;
                         mptsas_log(mpt, CE_NOTE, " Volume %d settings changed"
                             ", auto-config of hot-swap drives is %s"

@@ -7399,11 +7463,11 @@
                             (state >> 16) & 0xff);
                                 break;
                 }
                 case MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED:
                 {
-                        slots->m_raidconfig[config].m_raidvol[vol].m_state =
+                        mpt->m_raidconfig[config].m_raidvol[vol].m_state =
                             (uint8_t)state;
 
                         mptsas_log(mpt, CE_NOTE,
                             "Volume %d is now %s\n", vol,
                             state == MPI2_RAID_VOL_STATE_OPTIMAL

@@ -7421,11 +7485,11 @@
                             "state unknown");
                         break;
                 }
                 case MPI2_EVENT_IR_VOLUME_RC_STATUS_FLAGS_CHANGED:
                 {
-                        slots->m_raidconfig[config].m_raidvol[vol].
+                        mpt->m_raidconfig[config].m_raidvol[vol].
                             m_statusflags = state;
 
                         mptsas_log(mpt, CE_NOTE,
                             " Volume %d is now %s%s%s%s%s%s%s%s%s\n",
                             vol,

@@ -7570,22 +7634,18 @@
 
         mutex_enter(&mpt->m_mutex);
 
         mpt->m_restart_cmd_timeid = 0;
 
-        ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl,
-            MPTSAS_HASH_FIRST);
-        while (ptgt != NULL) {
+        for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL;
+            ptgt = refhash_next(mpt->m_targets, ptgt)) {
                 if (ptgt->m_reset_delay == 0) {
                         if (ptgt->m_t_throttle == QFULL_THROTTLE) {
                                 mptsas_set_throttle(mpt, ptgt,
                                     MAX_THROTTLE);
                         }
                 }
-
-                ptgt = (mptsas_target_t *)mptsas_hash_traverse(
-                    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
         }
         mptsas_restart_hba(mpt);
         mutex_exit(&mpt->m_mutex);
 }
 

@@ -7653,18 +7713,18 @@
          * out of duplicates.  This should be the normal case
          * for block and raw I/O.
          * If no duplicates, we have to scan through tag que and
          * find the longest timeout value and use it.  This is
          * going to take a while...
-         * Add 1 to m_n_slots to account for TM request.
+         * Add 1 to m_n_normal to account for TM request.
          */
         if (cmd->cmd_pkt->pkt_time == ptgt->m_timebase) {
                 if (--(ptgt->m_dups) == 0) {
                         if (ptgt->m_t_ncmds) {
                                 mptsas_cmd_t *ssp;
                                 uint_t n = 0;
-                                ushort_t nslots = (slots->m_n_slots + 1);
+                                ushort_t nslots = (slots->m_n_normal + 1);
                                 ushort_t i;
                                 /*
                                  * This crude check assumes we don't do
                                  * this too often which seems reasonable
                                  * for block and raw I/O.

@@ -8419,11 +8479,10 @@
 static int
 mptsas_do_scsi_reset(mptsas_t *mpt, uint16_t devhdl)
 {
         int             rval = FALSE;
         uint8_t         config, disk;
-        mptsas_slots_t  *slots = mpt->m_active;
 
         ASSERT(mutex_owned(&mpt->m_mutex));
 
         if (mptsas_debug_resets) {
                 mptsas_log(mpt, CE_WARN, "mptsas_do_scsi_reset: target=%d",

@@ -8434,13 +8493,13 @@
          * Issue a Target Reset message to the target specified but not to a
          * disk making up a raid volume.  Just look through the RAID config
          * Phys Disk list of DevHandles.  If the target's DevHandle is in this
          * list, then don't reset this target.
          */
-        for (config = 0; config < slots->m_num_raid_configs; config++) {
+        for (config = 0; config < mpt->m_num_raid_configs; config++) {
                 for (disk = 0; disk < MPTSAS_MAX_DISKS_IN_CONFIG; disk++) {
-                        if (devhdl == slots->m_raidconfig[config].
+                        if (devhdl == mpt->m_raidconfig[config].
                             m_physdisk_devhdl[disk]) {
                                 return (TRUE);
                         }
                 }
         }

@@ -8532,11 +8591,11 @@
          * Make sure the I/O Controller has flushed all cmds
          * that are associated with this target for a target reset
          * and target/lun for abort task set.
          * Account for TM requests, which use the last SMID.
          */
-        for (slot = 0; slot <= mpt->m_active->m_n_slots; slot++) {
+        for (slot = 0; slot <= mpt->m_active->m_n_normal; slot++) {
                 if ((cmd = slots->m_slot[slot]) == NULL)
                         continue;
                 reason = CMD_RESET;
                 stat = STAT_DEV_RESET;
                 switch (tasktype) {

@@ -8664,11 +8723,11 @@
          * The I/O Controller should have already sent back
          * all commands via the scsi I/O reply frame.  Make
          * sure all commands have been flushed.
          * Account for TM request, which use the last SMID.
          */
-        for (slot = 0; slot <= mpt->m_active->m_n_slots; slot++) {
+        for (slot = 0; slot <= mpt->m_active->m_n_normal; slot++) {
                 if ((cmd = slots->m_slot[slot]) == NULL)
                         continue;
 
                 if (cmd->cmd_flags & CFLAG_CMDIOC) {
                         /*

@@ -8779,19 +8838,17 @@
 static void
 mptsas_setup_bus_reset_delay(mptsas_t *mpt)
 {
         mptsas_target_t *ptgt = NULL;
 
+        ASSERT(MUTEX_HELD(&mpt->m_mutex));
+
         NDBG22(("mptsas_setup_bus_reset_delay"));
-        ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl,
-            MPTSAS_HASH_FIRST);
-        while (ptgt != NULL) {
+        for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL;
+            ptgt = refhash_next(mpt->m_targets, ptgt)) {
                 mptsas_set_throttle(mpt, ptgt, HOLD_THROTTLE);
                 ptgt->m_reset_delay = mpt->m_scsi_reset_delay;
-
-                ptgt = (mptsas_target_t *)mptsas_hash_traverse(
-                    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
         }
 
         mptsas_start_watch_reset_delay();
 }
 

@@ -8839,13 +8896,12 @@
 
         NDBG22(("mptsas_watch_reset_delay_subr: mpt=0x%p", (void *)mpt));
 
         ASSERT(mutex_owned(&mpt->m_mutex));
 
-        ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl,
-            MPTSAS_HASH_FIRST);
-        while (ptgt != NULL) {
+        for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL;
+            ptgt = refhash_next(mpt->m_targets, ptgt)) {
                 if (ptgt->m_reset_delay != 0) {
                         ptgt->m_reset_delay -=
                             MPTSAS_WATCH_RESET_DELAY_TICK;
                         if (ptgt->m_reset_delay <= 0) {
                                 ptgt->m_reset_delay = 0;

@@ -8854,13 +8910,10 @@
                                 restart++;
                         } else {
                                 done = -1;
                         }
                 }
-
-                ptgt = (mptsas_target_t *)mptsas_hash_traverse(
-                    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
         }
 
         if (restart > 0) {
                 mptsas_restart_hba(mpt);
         }

@@ -9160,11 +9213,10 @@
 mptsas_alloc_active_slots(mptsas_t *mpt, int flag)
 {
         mptsas_slots_t  *old_active = mpt->m_active;
         mptsas_slots_t  *new_active;
         size_t          size;
-        int             rval = -1, i;
 
         /*
          * if there are active commands, then we cannot
          * change size of active slots array.
          */

@@ -9172,35 +9224,25 @@
 
         size = MPTSAS_SLOTS_SIZE(mpt);
         new_active = kmem_zalloc(size, flag);
         if (new_active == NULL) {
                 NDBG1(("new active alloc failed"));
-                return (rval);
+                return (-1);
         }
         /*
          * Since SMID 0 is reserved and the TM slot is reserved, the
          * number of slots that can be used at any one time is
          * m_max_requests - 2.
          */
-        new_active->m_n_slots = (mpt->m_max_requests - 2);
+        new_active->m_n_normal = (mpt->m_max_requests - 2);
         new_active->m_size = size;
-        new_active->m_tags = 1;
-        if (old_active) {
-                new_active->m_tgttbl = old_active->m_tgttbl;
-                new_active->m_smptbl = old_active->m_smptbl;
-                new_active->m_num_raid_configs =
-                    old_active->m_num_raid_configs;
-                for (i = 0; i < new_active->m_num_raid_configs; i++) {
-                        new_active->m_raidconfig[i] =
-                            old_active->m_raidconfig[i];
-                }
+        new_active->m_rotor = 1;
+        if (old_active)
                 mptsas_free_active_slots(mpt);
-        }
         mpt->m_active = new_active;
-        rval = 0;
 
-        return (rval);
+        return (0);
 }
 
 static void
 mptsas_free_active_slots(mptsas_t *mpt)
 {

@@ -9341,10 +9383,12 @@
 {
         int             i;
         mptsas_cmd_t    *cmd;
         mptsas_target_t *ptgt = NULL;
 
+        ASSERT(MUTEX_HELD(&mpt->m_mutex));
+
         NDBG30(("mptsas_watchsubr: mpt=0x%p", (void *)mpt));
 
 #ifdef MPTSAS_TEST
         if (mptsas_enable_untagged) {
                 mptsas_test_untagged++;

@@ -9353,11 +9397,11 @@
 
         /*
          * Check for commands stuck in active slot
          * Account for TM requests, which use the last SMID.
          */
-        for (i = 0; i <= mpt->m_active->m_n_slots; i++) {
+        for (i = 0; i <= mpt->m_active->m_n_normal; i++) {
                 if ((cmd = mpt->m_active->m_slot[i]) != NULL) {
                         if ((cmd->cmd_flags & CFLAG_CMDIOC) == 0) {
                                 cmd->cmd_active_timeout -=
                                     mptsas_scsi_watchdog_tick;
                                 if (cmd->cmd_active_timeout <= 0) {

@@ -9387,13 +9431,12 @@
                                 }
                         }
                 }
         }
 
-        ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl,
-            MPTSAS_HASH_FIRST);
-        while (ptgt != NULL) {
+        for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL;
+            ptgt = refhash_next(mpt->m_targets, ptgt)) {
                 /*
                  * If we were draining due to a qfull condition,
                  * go back to full throttle.
                  */
                 if ((ptgt->m_t_throttle < MAX_THROTTLE) &&

@@ -9408,21 +9451,17 @@
 
                         if (ptgt->m_timebase <=
                             mptsas_scsi_watchdog_tick) {
                                 ptgt->m_timebase +=
                                     mptsas_scsi_watchdog_tick;
-                                ptgt = (mptsas_target_t *)mptsas_hash_traverse(
-                                    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
                                 continue;
                         }
 
                         ptgt->m_timeout -= mptsas_scsi_watchdog_tick;
 
                         if (ptgt->m_timeout < 0) {
                                 mptsas_cmd_timeout(mpt, ptgt->m_devhdl);
-                                ptgt = (mptsas_target_t *)mptsas_hash_traverse(
-                                    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
                                 continue;
                         }
 
                         if ((ptgt->m_timeout) <=
                             mptsas_scsi_watchdog_tick) {

@@ -9429,13 +9468,10 @@
                                 NDBG23(("pending timeout"));
                                 mptsas_set_throttle(mpt, ptgt,
                                     DRAIN_THROTTLE);
                         }
                 }
-
-                ptgt = (mptsas_target_t *)mptsas_hash_traverse(
-                    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
         }
 }
 
 /*
  * timeout recovery

@@ -9495,17 +9531,13 @@
 
         NDBG28(("mptsas_quiesce_bus"));
         mutex_enter(&mpt->m_mutex);
 
         /* Set all the throttles to zero */
-        ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl,
-            MPTSAS_HASH_FIRST);
-        while (ptgt != NULL) {
+        for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL;
+            ptgt = refhash_next(mpt->m_targets, ptgt)) {
                 mptsas_set_throttle(mpt, ptgt, HOLD_THROTTLE);
-
-                ptgt = (mptsas_target_t *)mptsas_hash_traverse(
-                    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
         }
 
         /* If there are any outstanding commands in the queue */
         if (mpt->m_ncmds) {
                 mpt->m_softstate |= MPTSAS_SS_DRAINING;

@@ -9514,17 +9546,13 @@
                 if (cv_wait_sig(&mpt->m_cv, &mpt->m_mutex) == 0) {
                         /*
                          * Quiesce has been interrupted
                          */
                         mpt->m_softstate &= ~MPTSAS_SS_DRAINING;
-                        ptgt = (mptsas_target_t *)mptsas_hash_traverse(
-                            &mpt->m_active->m_tgttbl, MPTSAS_HASH_FIRST);
-                        while (ptgt != NULL) {
+                        for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL;
+                            ptgt = refhash_next(mpt->m_targets, ptgt)) {
                                 mptsas_set_throttle(mpt, ptgt, MAX_THROTTLE);
-
-                                ptgt = (mptsas_target_t *)mptsas_hash_traverse(
-                                    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
                         }
                         mptsas_restart_hba(mpt);
                         if (mpt->m_quiesce_timeid != 0) {
                                 timeout_id_t tid = mpt->m_quiesce_timeid;
                                 mpt->m_quiesce_timeid = 0;

@@ -9555,17 +9583,13 @@
         mptsas_target_t *ptgt = NULL;
 
         NDBG28(("mptsas_unquiesce_bus"));
         mutex_enter(&mpt->m_mutex);
         mpt->m_softstate &= ~MPTSAS_SS_QUIESCED;
-        ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl,
-            MPTSAS_HASH_FIRST);
-        while (ptgt != NULL) {
+        for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL;
+            ptgt = refhash_next(mpt->m_targets, ptgt)) {
                 mptsas_set_throttle(mpt, ptgt, MAX_THROTTLE);
-
-                ptgt = (mptsas_target_t *)mptsas_hash_traverse(
-                    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
         }
         mptsas_restart_hba(mpt);
         mutex_exit(&mpt->m_mutex);
         return (0);
 }

@@ -9585,17 +9609,13 @@
                 } else {
                         /*
                          * The throttle may have been reset because
                          * of a SCSI bus reset
                          */
-                        ptgt = (mptsas_target_t *)mptsas_hash_traverse(
-                            &mpt->m_active->m_tgttbl, MPTSAS_HASH_FIRST);
-                        while (ptgt != NULL) {
+                        for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL;
+                            ptgt = refhash_next(mpt->m_targets, ptgt)) {
                                 mptsas_set_throttle(mpt, ptgt, HOLD_THROTTLE);
-
-                                ptgt = (mptsas_target_t *)mptsas_hash_traverse(
-                                    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
                         }
 
                         mpt->m_quiesce_timeid = timeout(mptsas_ncmds_checkdrain,
                             mpt, (MPTSAS_QUIESCE_TIMEOUT *
                             drv_usectohz(1000000)));

@@ -11323,20 +11343,12 @@
             (lc.Command == MPTSAS_LEDCTL_FLAG_GET && (mode & FREAD) == 0))
                 return (EACCES);
 
         /* Locate the target we're interrogating... */
         mutex_enter(&mpt->m_mutex);
-        ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl,
-            MPTSAS_HASH_FIRST);
-        while (ptgt != NULL) {
-                if (ptgt->m_enclosure == lc.Enclosure &&
-                    ptgt->m_slot_num == lc.Slot) {
-                        break;
-                }
-                ptgt = (mptsas_target_t *)mptsas_hash_traverse(
-                    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
-        }
+        ptgt = refhash_linear_search(mpt->m_targets,
+            mptsas_target_eval_slot, &lc);
         if (ptgt == NULL) {
                 /* We could not find a target for that enclosure/slot. */
                 mutex_exit(&mpt->m_mutex);
                 return (ENOENT);
         }

@@ -11383,16 +11395,13 @@
                 return (EFAULT);
         }
 
         /* Find out how many targets there are. */
         mutex_enter(&mpt->m_mutex);
-        ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl,
-            MPTSAS_HASH_FIRST);
-        while (ptgt != NULL) {
+        for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL;
+            ptgt = refhash_next(mpt->m_targets, ptgt)) {
                 count++;
-                ptgt = (mptsas_target_t *)mptsas_hash_traverse(
-                    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
         }
         mutex_exit(&mpt->m_mutex);
 
         /*
          * If we haven't been asked to copy out information on each target,

@@ -11413,29 +11422,26 @@
         }
 
         di = kmem_zalloc(count * sizeof (mptsas_disk_info_t), KM_SLEEP);
 
         mutex_enter(&mpt->m_mutex);
-        ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl,
-            MPTSAS_HASH_FIRST);
-        while (ptgt != NULL) {
+        for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL;
+            ptgt = refhash_next(mpt->m_targets, ptgt)) {
                 if (i >= count) {
                         /*
                          * The number of targets changed while we weren't
                          * looking, so give up.
                          */
+                        refhash_rele(mpt->m_targets, ptgt);
                         mutex_exit(&mpt->m_mutex);
                         kmem_free(di, count * sizeof (mptsas_disk_info_t));
                         return (EAGAIN);
                 }
                 di[i].Instance = mpt->m_instance;
                 di[i].Enclosure = ptgt->m_enclosure;
                 di[i].Slot = ptgt->m_slot_num;
-                di[i].SasAddress = ptgt->m_sas_wwn;
-
-                ptgt = (mptsas_target_t *)mptsas_hash_traverse(
-                    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
+                di[i].SasAddress = ptgt->m_addr.mta_wwn;
                 i++;
         }
         mutex_exit(&mpt->m_mutex);
         STRUCT_FSET(gdi, DiskCount, i);
 

@@ -11737,17 +11743,13 @@
         mpt->m_in_reset = TRUE;
 
         /*
          * Set all throttles to HOLD
          */
-        ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl,
-            MPTSAS_HASH_FIRST);
-        while (ptgt != NULL) {
+        for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL;
+            ptgt = refhash_next(mpt->m_targets, ptgt)) {
                 mptsas_set_throttle(mpt, ptgt, HOLD_THROTTLE);
-
-                ptgt = (mptsas_target_t *)mptsas_hash_traverse(
-                    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
         }
 
         /*
          * Disable interrupts
          */

@@ -11779,17 +11781,13 @@
         }
 
         /*
          * Reset the throttles
          */
-        ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl,
-            MPTSAS_HASH_FIRST);
-        while (ptgt != NULL) {
+        for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL;
+            ptgt = refhash_next(mpt->m_targets, ptgt)) {
                 mptsas_set_throttle(mpt, ptgt, MAX_THROTTLE);
-
-                ptgt = (mptsas_target_t *)mptsas_hash_traverse(
-                    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
         }
 
         mptsas_doneq_empty(mpt);
         mptsas_restart_hba(mpt);
 

@@ -11851,10 +11849,16 @@
         if (mptsas_ioc_get_facts(mpt) == DDI_FAILURE) {
                 mptsas_log(mpt, CE_WARN, "mptsas_ioc_get_facts failed");
                 goto fail;
         }
 
+        mpt->m_targets = refhash_create(MPTSAS_TARGET_BUCKET_COUNT,
+            mptsas_target_addr_hash, mptsas_target_addr_cmp,
+            mptsas_target_free, sizeof (mptsas_target_t),
+            offsetof(mptsas_target_t, m_link),
+            offsetof(mptsas_target_t, m_addr), KM_SLEEP);
+
         if (mptsas_alloc_active_slots(mpt, KM_SLEEP)) {
                 goto fail;
         }
         /*
          * Allocate request message frames, reply free queue, reply descriptor

@@ -12489,11 +12493,10 @@
         int             rval;
         uint32_t        dev_info;
         uint64_t        sas_wwn;
         mptsas_phymask_t phymask;
         uint8_t         physport, phynum, config, disk;
-        mptsas_slots_t  *slots = mpt->m_active;
         uint64_t        devicename;
         uint16_t        pdev_hdl;
         mptsas_target_t *tmp_tgt = NULL;
         uint16_t        bay_num, enclosure;
 

@@ -12516,23 +12519,23 @@
 
         /*
          * Check if the dev handle is for a Phys Disk. If so, set return value
          * and exit.  Don't add Phys Disks to hash.
          */
-        for (config = 0; config < slots->m_num_raid_configs; config++) {
+        for (config = 0; config < mpt->m_num_raid_configs; config++) {
                 for (disk = 0; disk < MPTSAS_MAX_DISKS_IN_CONFIG; disk++) {
-                        if (*dev_handle == slots->m_raidconfig[config].
+                        if (*dev_handle == mpt->m_raidconfig[config].
                             m_physdisk_devhdl[disk]) {
                                 rval = DEV_INFO_PHYS_DISK;
                                 return (rval);
                         }
                 }
         }
 
         /*
          * Get SATA Device Name from SAS device page0 for
-         * sata device, if device name doesn't exist, set m_sas_wwn to
+         * sata device, if device name doesn't exist, set mta_wwn to
          * 0 for direct attached SATA. For the device behind the expander
          * we still can use STP address assigned by expander.
          */
         if (dev_info & (MPI2_SAS_DEVICE_INFO_SATA_DEVICE |
             MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE)) {

@@ -12555,11 +12558,11 @@
                         sas_wwn = 0;
                 }
         }
 
         phymask = mptsas_physport_to_phymask(mpt, physport);
-        *pptgt = mptsas_tgt_alloc(&slots->m_tgttbl, *dev_handle, sas_wwn,
+        *pptgt = mptsas_tgt_alloc(mpt, *dev_handle, sas_wwn,
             dev_info, phymask, phynum);
         if (*pptgt == NULL) {
                 mptsas_log(mpt, CE_WARN, "Failed to allocated target"
                     "structure!");
                 rval = DEV_INFO_FAIL_ALLOC;

@@ -12985,11 +12988,11 @@
                  * TODO Another senario is, we hotplug the same disk
                  * on the same slot, the devhdl changed, is this
                  * possible?
                  * tgt_private->t_private != ptgt
                  */
-                if (sasaddr != ptgt->m_sas_wwn) {
+                if (sasaddr != ptgt->m_addr.mta_wwn) {
                         /*
                          * The device has changed although the devhdl is the
                          * same (Enclosure mapping mode, change drive on the
                          * same slot)
                          */

@@ -13014,17 +13017,17 @@
 mptsas_config_one_phy(dev_info_t *pdip, uint8_t phy, int lun,
     dev_info_t **lundip)
 {
         int             rval;
         mptsas_t        *mpt = DIP2MPT(pdip);
-        int             phymask;
+        mptsas_phymask_t phymask;
         mptsas_target_t *ptgt = NULL;
 
         /*
          * Get the physical port associated to the iport
          */
-        phymask = ddi_prop_get_int(DDI_DEV_T_ANY, pdip, 0,
+        phymask = (mptsas_phymask_t)ddi_prop_get_int(DDI_DEV_T_ANY, pdip, 0,
             "phymask", 0);
 
         ptgt = mptsas_phy_to_tgt(mpt, phymask, phy);
         if (ptgt == NULL) {
                 /*

@@ -13107,11 +13110,11 @@
         uint64_t                sas_wwn = 0;
         uint8_t                 phy = 0xFF;
         uint32_t                dev_info = 0;
 
         mutex_enter(&mpt->m_mutex);
-        sas_wwn = ptgt->m_sas_wwn;
+        sas_wwn = ptgt->m_addr.mta_wwn;
         phy = ptgt->m_phynum;
         dev_info = ptgt->m_deviceinfo;
         mutex_exit(&mpt->m_mutex);
 
         if (sas_wwn == 0) {

@@ -13222,11 +13225,12 @@
         struct scsi_inquiry     *sd_inq = NULL;
         mptsas_t                *mpt = DIP2MPT(pdip);
         mptsas_target_t         *ptgt = NULL;
 
         mutex_enter(&mpt->m_mutex);
-        ptgt = mptsas_search_by_devhdl(&mpt->m_active->m_tgttbl, target);
+        ptgt = refhash_linear_search(mpt->m_targets,
+            mptsas_target_eval_devhdl, &target);
         mutex_exit(&mpt->m_mutex);
         if (ptgt == NULL) {
                 mptsas_log(mpt, CE_WARN, "Volume with VolDevHandle of 0x%x "
                     "not found.", target);
                 return (rval);

@@ -13255,22 +13259,21 @@
 {
         mptsas_t        *mpt = DIP2MPT(pdip);
         int             config, vol;
         int             target;
         dev_info_t      *lundip = NULL;
-        mptsas_slots_t  *slots = mpt->m_active;
 
         /*
          * Get latest RAID info and search for any Volume DevHandles.  If any
          * are found, configure the volume.
          */
         mutex_enter(&mpt->m_mutex);
-        for (config = 0; config < slots->m_num_raid_configs; config++) {
+        for (config = 0; config < mpt->m_num_raid_configs; config++) {
                 for (vol = 0; vol < MPTSAS_MAX_RAIDVOLS; vol++) {
-                        if (slots->m_raidconfig[config].m_raidvol[vol].m_israid
+                        if (mpt->m_raidconfig[config].m_raidvol[vol].m_israid
                             == 1) {
-                                target = slots->m_raidconfig[config].
+                                target = mpt->m_raidconfig[config].
                                     m_raidvol[vol].m_raidhandle;
                                 mutex_exit(&mpt->m_mutex);
                                 (void) mptsas_config_raid(pdip, target,
                                     &lundip);
                                 mutex_enter(&mpt->m_mutex);

@@ -13294,11 +13297,11 @@
         char            *addr;
         char            *nodename;
         mptsas_t        *mpt = DIP2MPT(pdip);
 
         mutex_enter(&mpt->m_mutex);
-        wwid = ptgt->m_sas_wwn;
+        wwid = ptgt->m_addr.mta_wwn;
         mutex_exit(&mpt->m_mutex);
 
         child = ddi_get_child(pdip);
         while (child) {
                 find = 0;

@@ -13398,11 +13401,11 @@
                 if (mptsas_get_sas_expander_page0(mpt, page_address, &smp_node)
                     != DDI_SUCCESS) {
                         break;
                 }
                 mpt->m_smp_devhdl = dev_handle = smp_node.m_devhdl;
-                (void) mptsas_smp_alloc(&mpt->m_active->m_smptbl, &smp_node);
+                (void) mptsas_smp_alloc(mpt, &smp_node);
         }
 
         /*
          * Config target devices
          */

@@ -13430,28 +13433,17 @@
         }
 
 }
 
 void
-mptsas_invalid_hashtab(mptsas_hash_table_t *hashtab)
-{
-        mptsas_hash_data_t *data;
-        data = mptsas_hash_traverse(hashtab, MPTSAS_HASH_FIRST);
-        while (data != NULL) {
-                data->devhdl = MPTSAS_INVALID_DEVHDL;
-                data->device_info = 0;
-                /*
-                 * For tgttbl, clear dr_flag.
-                 */
-                data->dr_flag = MPTSAS_DR_INACTIVE;
-                data = mptsas_hash_traverse(hashtab, MPTSAS_HASH_NEXT);
-        }
-}
-
-void
 mptsas_update_driver_data(struct mptsas *mpt)
 {
+        mptsas_target_t *tp;
+        mptsas_smp_t *sp;
+
+        ASSERT(MUTEX_HELD(&mpt->m_mutex));
+
         /*
          * TODO after hard reset, update the driver data structures
          * 1. update port/phymask mapping table mpt->m_phy_info
          * 2. invalid all the entries in hash table
          *    m_devhdl = 0xffff and m_deviceinfo = 0

@@ -13458,13 +13450,28 @@
          * 3. call sas_device_page/expander_page to update hash table
          */
         mptsas_update_phymask(mpt);
         /*
          * Invalid the existing entries
+         *
+         * XXX - It seems like we should just delete everything here.  We are
+         * holding the lock and are about to refresh all the targets in both
+         * hashes anyway.  Given the path we're in, what outstanding async
+         * event could possibly be trying to reference one of these things
+         * without taking the lock, and how would that be useful anyway?
          */
-        mptsas_invalid_hashtab(&mpt->m_active->m_tgttbl);
-        mptsas_invalid_hashtab(&mpt->m_active->m_smptbl);
+        for (tp = refhash_first(mpt->m_targets); tp != NULL;
+            tp = refhash_next(mpt->m_targets, tp)) {
+                tp->m_devhdl = MPTSAS_INVALID_DEVHDL;
+                tp->m_deviceinfo = 0;
+                tp->m_dr_flag = MPTSAS_DR_INACTIVE;
+        }
+        for (sp = refhash_first(mpt->m_smp_targets); sp != NULL;
+            sp = refhash_next(mpt->m_smp_targets, sp)) {
+                sp->m_devhdl = MPTSAS_INVALID_DEVHDL;
+                sp->m_deviceinfo = 0;
+        }
         mpt->m_done_traverse_dev = 0;
         mpt->m_done_traverse_smp = 0;
         mpt->m_dev_handle = mpt->m_smp_devhdl = MPTSAS_INVALID_DEVHDL;
         mptsas_update_hashtab(mpt);
 }

@@ -13497,36 +13504,29 @@
 
         if (!mpt->m_done_traverse_dev || !mpt->m_done_traverse_smp) {
                 mptsas_update_hashtab(mpt);
         }
 
-        psmp = (mptsas_smp_t *)mptsas_hash_traverse(&mpt->m_active->m_smptbl,
-            MPTSAS_HASH_FIRST);
-        while (psmp != NULL) {
-                phy_mask = psmp->m_phymask;
+        for (psmp = refhash_first(mpt->m_smp_targets); psmp != NULL;
+            psmp = refhash_next(mpt->m_smp_targets, psmp)) {
+                phy_mask = psmp->m_addr.mta_phymask;
                 if (phy_mask == phymask) {
                         smpdip = NULL;
                         mutex_exit(&mpt->m_mutex);
                         (void) mptsas_online_smp(pdip, psmp, &smpdip);
                         mutex_enter(&mpt->m_mutex);
                 }
-                psmp = (mptsas_smp_t *)mptsas_hash_traverse(
-                    &mpt->m_active->m_smptbl, MPTSAS_HASH_NEXT);
         }
 
-        ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl,
-            MPTSAS_HASH_FIRST);
-        while (ptgt != NULL) {
-                phy_mask = ptgt->m_phymask;
+        for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL;
+            ptgt = refhash_next(mpt->m_targets, ptgt)) {
+                phy_mask = ptgt->m_addr.mta_phymask;
                 if (phy_mask == phymask) {
                         mutex_exit(&mpt->m_mutex);
                         (void) mptsas_config_target(pdip, ptgt);
                         mutex_enter(&mpt->m_mutex);
                 }
-
-                ptgt = (mptsas_target_t *)mptsas_hash_traverse(
-                    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
         }
         mutex_exit(&mpt->m_mutex);
 }
 
 static int

@@ -13704,11 +13704,11 @@
         int             rval = DDI_FAILURE;
         char            *devname;
         char            wwn_str[MPTSAS_WWN_STRLEN];
         dev_info_t      *cdip;
 
-        (void) sprintf(wwn_str, "%"PRIx64, smp_node->m_sasaddr);
+        (void) sprintf(wwn_str, "%"PRIx64, smp_node->m_addr.mta_wwn);
 
         cdip = mptsas_find_smp_child(pdip, wwn_str);
 
         if (cdip == NULL)
                 return (DDI_SUCCESS);

@@ -13984,11 +13984,11 @@
         char                    pdev_wwn_str[MPTSAS_WWN_STRLEN];
         uint32_t                dev_info;
 
         mutex_enter(&mpt->m_mutex);
         target = ptgt->m_devhdl;
-        sas_wwn = ptgt->m_sas_wwn;
+        sas_wwn = ptgt->m_addr.mta_wwn;
         devinfo = ptgt->m_deviceinfo;
         phy = ptgt->m_phynum;
         mutex_exit(&mpt->m_mutex);
 
         if (sas_wwn) {

@@ -14333,11 +14333,11 @@
         uint32_t                dev_info;
         int64_t                 lun64 = 0;
 
         mutex_enter(&mpt->m_mutex);
         target = ptgt->m_devhdl;
-        sas_wwn = ptgt->m_sas_wwn;
+        sas_wwn = ptgt->m_addr.mta_wwn;
         devinfo = ptgt->m_deviceinfo;
         phy = ptgt->m_phynum;
         mutex_exit(&mpt->m_mutex);
 
         /*

@@ -14452,11 +14452,11 @@
 
                 /*
                  * The following code is to set properties for SM-HBA support,
                  * it doesn't apply to RAID volumes
                  */
-                if (ptgt->m_phymask == 0)
+                if (ptgt->m_addr.mta_phymask == 0)
                         goto phys_raid_lun;
 
                 mutex_enter(&mpt->m_mutex);
 
                 page_address = (MPI2_SAS_DEVICE_PGAD_FORM_HANDLE &

@@ -14606,11 +14606,11 @@
                         }
                 }
                 /*
                  * Create the phy-num property for non-raid disk
                  */
-                if (ptgt->m_phymask != 0) {
+                if (ptgt->m_addr.mta_phymask != 0) {
                         if (ndi_prop_update_int(DDI_DEV_T_NONE,
                             *lun_dip, "phy-num", ptgt->m_phynum) !=
                             DDI_PROP_SUCCESS) {
                                 mptsas_log(mpt, CE_WARN, "mptsas driver "
                                     "failed to create phy-num property for "

@@ -14728,17 +14728,17 @@
         char            *iport = NULL;
         mptsas_phymask_t        phy_mask = 0;
         uint16_t        attached_devhdl;
         uint16_t        bay_num, enclosure;
 
-        (void) sprintf(wwn_str, "%"PRIx64, smp_node->m_sasaddr);
+        (void) sprintf(wwn_str, "%"PRIx64, smp_node->m_addr.mta_wwn);
 
         /*
          * Probe smp device, prevent the node of removed device from being
          * configured succesfully
          */
-        if (mptsas_probe_smp(pdip, smp_node->m_sasaddr) != NDI_SUCCESS) {
+        if (mptsas_probe_smp(pdip, smp_node->m_addr.mta_wwn) != NDI_SUCCESS) {
                 return (DDI_FAILURE);
         }
 
         if ((*smp_dip = mptsas_find_smp_child(pdip, wwn_str)) != NULL) {
                 return (DDI_SUCCESS);

@@ -14762,11 +14762,11 @@
                             "property for smp device %s (sas_wwn)",
                             wwn_str);
                         ndi_rtn = NDI_FAILURE;
                         goto smp_create_done;
                 }
-                (void) sprintf(wwn_str, "w%"PRIx64, smp_node->m_sasaddr);
+                (void) sprintf(wwn_str, "w%"PRIx64, smp_node->m_addr.mta_wwn);
                 if (ndi_prop_update_string(DDI_DEV_T_NONE,
                     *smp_dip, SCSI_ADDR_PROP_TARGET_PORT, wwn_str) !=
                     DDI_PROP_SUCCESS) {
                         mptsas_log(mpt, CE_WARN, "mptsas unable to create "
                             "property for iport target-port %s (sas_wwn)",

@@ -15046,11 +15046,11 @@
 /*
  * If we didn't get a match, we need to get sas page0 for each device, and
  * untill we get a match. If failed, return NULL
  */
 static mptsas_target_t *
-mptsas_phy_to_tgt(mptsas_t *mpt, int phymask, uint8_t phy)
+mptsas_phy_to_tgt(mptsas_t *mpt, mptsas_phymask_t phymask, uint8_t phy)
 {
         int             i, j = 0;
         int             rval = 0;
         uint16_t        cur_handle;
         uint32_t        page_address;

@@ -15078,22 +15078,17 @@
         if (mpt->m_phy_info[phy].phy_mask != phymask)
                 return (NULL);
 
         mutex_enter(&mpt->m_mutex);
 
-        ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl,
-            MPTSAS_HASH_FIRST);
-        while (ptgt != NULL) {
-                        if ((ptgt->m_sas_wwn == 0) && (ptgt->m_phynum == phy)) {
+        ptgt = refhash_linear_search(mpt->m_targets, mptsas_target_eval_nowwn,
+            &phy);
+        if (ptgt != NULL) {
                         mutex_exit(&mpt->m_mutex);
                         return (ptgt);
                 }
 
-                ptgt = (mptsas_target_t *)mptsas_hash_traverse(
-                    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
-        }
-
         if (mpt->m_done_traverse_dev) {
                 mutex_exit(&mpt->m_mutex);
                 return (NULL);
         }
 

@@ -15113,37 +15108,39 @@
                     (rval == DEV_INFO_PHYS_DISK)) {
                         continue;
                 }
                 mpt->m_dev_handle = cur_handle;
 
-                if ((ptgt->m_sas_wwn == 0) && (ptgt->m_phynum == phy)) {
+                if ((ptgt->m_addr.mta_wwn == 0) && (ptgt->m_phynum == phy)) {
                         break;
                 }
         }
 
         mutex_exit(&mpt->m_mutex);
         return (ptgt);
 }
 
 /*
- * The ptgt->m_sas_wwn contains the wwid for each disk.
+ * The ptgt->m_addr.mta_wwn contains the wwid for each disk.
  * For Raid volumes, we need to check m_raidvol[x].m_raidwwid
  * If we didn't get a match, we need to get sas page0 for each device, and
  * untill we get a match
  * If failed, return NULL
  */
 static mptsas_target_t *
-mptsas_wwid_to_ptgt(mptsas_t *mpt, int phymask, uint64_t wwid)
+mptsas_wwid_to_ptgt(mptsas_t *mpt, mptsas_phymask_t phymask, uint64_t wwid)
 {
         int             rval = 0;
         uint16_t        cur_handle;
         uint32_t        page_address;
         mptsas_target_t *tmp_tgt = NULL;
+        mptsas_target_addr_t addr;
 
+        addr.mta_wwn = wwid;
+        addr.mta_phymask = phymask;
         mutex_enter(&mpt->m_mutex);
-        tmp_tgt = (struct mptsas_target *)mptsas_hash_search(
-            &mpt->m_active->m_tgttbl, wwid, phymask);
+        tmp_tgt = refhash_lookup(mpt->m_targets, &addr);
         if (tmp_tgt != NULL) {
                 mutex_exit(&mpt->m_mutex);
                 return (tmp_tgt);
         }
 

@@ -15151,12 +15148,11 @@
                 /*
                  * It's IR volume
                  */
                 rval = mptsas_get_raid_info(mpt);
                 if (rval) {
-                        tmp_tgt = (struct mptsas_target *)mptsas_hash_search(
-                            &mpt->m_active->m_tgttbl, wwid, phymask);
+                        tmp_tgt = refhash_lookup(mpt->m_targets, &addr);
                 }
                 mutex_exit(&mpt->m_mutex);
                 return (tmp_tgt);
         }
 

@@ -15165,11 +15161,11 @@
                 return (NULL);
         }
 
         /* If didn't get a match, come here */
         cur_handle = mpt->m_dev_handle;
-        for (; ; ) {
+        for (;;) {
                 tmp_tgt = NULL;
                 page_address = (MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE &
                     MPI2_SAS_DEVICE_PGAD_FORM_MASK) | cur_handle;
                 rval = mptsas_get_target_device_info(mpt, page_address,
                     &cur_handle, &tmp_tgt);

@@ -15181,31 +15177,34 @@
                 if ((rval == DEV_INFO_WRONG_DEVICE_TYPE) ||
                     (rval == DEV_INFO_PHYS_DISK)) {
                         continue;
                 }
                 mpt->m_dev_handle = cur_handle;
-                if ((tmp_tgt->m_sas_wwn) && (tmp_tgt->m_sas_wwn == wwid) &&
-                    (tmp_tgt->m_phymask == phymask)) {
+                if ((tmp_tgt->m_addr.mta_wwn) &&
+                    (tmp_tgt->m_addr.mta_wwn == wwid) &&
+                    (tmp_tgt->m_addr.mta_phymask == phymask)) {
                         break;
                 }
         }
 
         mutex_exit(&mpt->m_mutex);
         return (tmp_tgt);
 }
 
 static mptsas_smp_t *
-mptsas_wwid_to_psmp(mptsas_t *mpt, int phymask, uint64_t wwid)
+mptsas_wwid_to_psmp(mptsas_t *mpt, mptsas_phymask_t phymask, uint64_t wwid)
 {
         int             rval = 0;
         uint16_t        cur_handle;
         uint32_t        page_address;
         mptsas_smp_t    smp_node, *psmp = NULL;
+        mptsas_target_addr_t addr;
 
+        addr.mta_wwn = wwid;
+        addr.mta_phymask = phymask;
         mutex_enter(&mpt->m_mutex);
-        psmp = (struct mptsas_smp *)mptsas_hash_search(&mpt->m_active->m_smptbl,
-            wwid, phymask);
+        psmp = refhash_lookup(mpt->m_smp_targets, &addr);
         if (psmp != NULL) {
                 mutex_exit(&mpt->m_mutex);
                 return (psmp);
         }
 

@@ -15214,286 +15213,105 @@
                 return (NULL);
         }
 
         /* If didn't get a match, come here */
         cur_handle = mpt->m_smp_devhdl;
-        for (; ; ) {
+        for (;;) {
                 psmp = NULL;
                 page_address = (MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL &
                     MPI2_SAS_EXPAND_PGAD_FORM_MASK) | (uint32_t)cur_handle;
                 rval = mptsas_get_sas_expander_page0(mpt, page_address,
                     &smp_node);
                 if (rval != DDI_SUCCESS) {
                         break;
                 }
                 mpt->m_smp_devhdl = cur_handle = smp_node.m_devhdl;
-                psmp = mptsas_smp_alloc(&mpt->m_active->m_smptbl, &smp_node);
+                psmp = mptsas_smp_alloc(mpt, &smp_node);
                 ASSERT(psmp);
-                if ((psmp->m_sasaddr) && (psmp->m_sasaddr == wwid) &&
-                    (psmp->m_phymask == phymask)) {
+                if ((psmp->m_addr.mta_wwn) && (psmp->m_addr.mta_wwn == wwid) &&
+                    (psmp->m_addr.mta_phymask == phymask)) {
                         break;
                 }
         }
 
         mutex_exit(&mpt->m_mutex);
         return (psmp);
 }
 
-/* helper functions using hash */
-
-/*
- * Can't have duplicate entries for same devhdl,
- * if there are invalid entries, the devhdl should be set to 0xffff
- */
-static void *
-mptsas_search_by_devhdl(mptsas_hash_table_t *hashtab, uint16_t devhdl)
-{
-        mptsas_hash_data_t *data;
-
-        data = mptsas_hash_traverse(hashtab, MPTSAS_HASH_FIRST);
-        while (data != NULL) {
-                if (data->devhdl == devhdl) {
-                        break;
-                }
-                data = mptsas_hash_traverse(hashtab, MPTSAS_HASH_NEXT);
-        }
-        return (data);
-}
-
 mptsas_target_t *
-mptsas_tgt_alloc(mptsas_hash_table_t *hashtab, uint16_t devhdl, uint64_t wwid,
+mptsas_tgt_alloc(mptsas_t *mpt, uint16_t devhdl, uint64_t wwid,
     uint32_t devinfo, mptsas_phymask_t phymask, uint8_t phynum)
 {
         mptsas_target_t *tmp_tgt = NULL;
+        mptsas_target_addr_t addr;
 
-        tmp_tgt = mptsas_hash_search(hashtab, wwid, phymask);
+        addr.mta_wwn = wwid;
+        addr.mta_phymask = phymask;
+        tmp_tgt = refhash_lookup(mpt->m_targets, &addr);
         if (tmp_tgt != NULL) {
                 NDBG20(("Hash item already exist"));
                 tmp_tgt->m_deviceinfo = devinfo;
-                tmp_tgt->m_devhdl = devhdl;
+                tmp_tgt->m_devhdl = devhdl;     /* XXX - duplicate? */
                 return (tmp_tgt);
         }
         tmp_tgt = kmem_zalloc(sizeof (struct mptsas_target), KM_SLEEP);
         if (tmp_tgt == NULL) {
                 cmn_err(CE_WARN, "Fatal, allocated tgt failed");
                 return (NULL);
         }
         tmp_tgt->m_devhdl = devhdl;
-        tmp_tgt->m_sas_wwn = wwid;
+        tmp_tgt->m_addr.mta_wwn = wwid;
         tmp_tgt->m_deviceinfo = devinfo;
-        tmp_tgt->m_phymask = phymask;
+        tmp_tgt->m_addr.mta_phymask = phymask;
         tmp_tgt->m_phynum = phynum;
         /* Initialized the tgt structure */
         tmp_tgt->m_qfull_retries = QFULL_RETRIES;
         tmp_tgt->m_qfull_retry_interval =
             drv_usectohz(QFULL_RETRY_INTERVAL * 1000);
         tmp_tgt->m_t_throttle = MAX_THROTTLE;
 
-        mptsas_hash_add(hashtab, tmp_tgt);
+        refhash_insert(mpt->m_targets, tmp_tgt);
 
         return (tmp_tgt);
 }
 
 static void
-mptsas_tgt_free(mptsas_hash_table_t *hashtab, uint64_t wwid,
-    mptsas_phymask_t phymask)
+mptsas_smp_target_copy(mptsas_smp_t *src, mptsas_smp_t *dst)
 {
-        mptsas_target_t *tmp_tgt;
-        tmp_tgt = mptsas_hash_rem(hashtab, wwid, phymask);
-        if (tmp_tgt == NULL) {
-                cmn_err(CE_WARN, "Tgt not found, nothing to free");
-        } else {
-                kmem_free(tmp_tgt, sizeof (struct mptsas_target));
-        }
+        dst->m_devhdl = src->m_devhdl;
+        dst->m_deviceinfo = src->m_deviceinfo;
+        dst->m_pdevhdl = src->m_pdevhdl;
+        dst->m_pdevinfo = src->m_pdevinfo;
 }
 
-/*
- * Return the entry in the hash table
- */
 static mptsas_smp_t *
-mptsas_smp_alloc(mptsas_hash_table_t *hashtab, mptsas_smp_t *data)
+mptsas_smp_alloc(mptsas_t *mpt, mptsas_smp_t *data)
 {
-        uint64_t key1 = data->m_sasaddr;
-        mptsas_phymask_t key2 = data->m_phymask;
+        mptsas_target_addr_t addr;
         mptsas_smp_t *ret_data;
 
-        ret_data = mptsas_hash_search(hashtab, key1, key2);
+        addr.mta_wwn = data->m_addr.mta_wwn;
+        addr.mta_phymask = data->m_addr.mta_phymask;
+        ret_data = refhash_lookup(mpt->m_smp_targets, &addr);
+        /*
+         * If there's already a matching SMP target, update its fields
+         * in place.  Since the address is not changing, it's safe to do
+         * this.  We cannot just bcopy() here because the structure we've
+         * been given has invalid hash links.
+         */
         if (ret_data != NULL) {
-                bcopy(data, ret_data, sizeof (mptsas_smp_t));
+                mptsas_smp_target_copy(data, ret_data);
                 return (ret_data);
         }
 
         ret_data = kmem_alloc(sizeof (mptsas_smp_t), KM_SLEEP);
         bcopy(data, ret_data, sizeof (mptsas_smp_t));
-        mptsas_hash_add(hashtab, ret_data);
+        refhash_insert(mpt->m_smp_targets, ret_data);
         return (ret_data);
 }
 
-static void
-mptsas_smp_free(mptsas_hash_table_t *hashtab, uint64_t wwid,
-    mptsas_phymask_t phymask)
-{
-        mptsas_smp_t *tmp_smp;
-        tmp_smp = mptsas_hash_rem(hashtab, wwid, phymask);
-        if (tmp_smp == NULL) {
-                cmn_err(CE_WARN, "Smp element not found, nothing to free");
-        } else {
-                kmem_free(tmp_smp, sizeof (struct mptsas_smp));
-        }
-}
-
 /*
- * Hash operation functions
- * key1 is the sas_wwn, key2 is the phymask
- */
-static void
-mptsas_hash_init(mptsas_hash_table_t *hashtab)
-{
-        if (hashtab == NULL) {
-                return;
-        }
-        bzero(hashtab->head, sizeof (mptsas_hash_node_t) *
-            MPTSAS_HASH_ARRAY_SIZE);
-        hashtab->cur = NULL;
-        hashtab->line = 0;
-}
-
-static void
-mptsas_hash_uninit(mptsas_hash_table_t *hashtab, size_t datalen)
-{
-        uint16_t line = 0;
-        mptsas_hash_node_t *cur = NULL, *last = NULL;
-
-        if (hashtab == NULL) {
-                return;
-        }
-        for (line = 0; line < MPTSAS_HASH_ARRAY_SIZE; line++) {
-                cur = hashtab->head[line];
-                while (cur != NULL) {
-                        last = cur;
-                        cur = cur->next;
-                        kmem_free(last->data, datalen);
-                        kmem_free(last, sizeof (mptsas_hash_node_t));
-                }
-        }
-}
-
-/*
- * You must guarantee the element doesn't exist in the hash table
- * before you call mptsas_hash_add()
- */
-static void
-mptsas_hash_add(mptsas_hash_table_t *hashtab, void *data)
-{
-        uint64_t key1 = ((mptsas_hash_data_t *)data)->key1;
-        mptsas_phymask_t key2 = ((mptsas_hash_data_t *)data)->key2;
-        mptsas_hash_node_t **head = NULL;
-        mptsas_hash_node_t *node = NULL;
-
-        if (hashtab == NULL) {
-                return;
-        }
-        ASSERT(mptsas_hash_search(hashtab, key1, key2) == NULL);
-        node = kmem_zalloc(sizeof (mptsas_hash_node_t), KM_NOSLEEP);
-        node->data = data;
-
-        head = &(hashtab->head[key1 % MPTSAS_HASH_ARRAY_SIZE]);
-        if (*head == NULL) {
-                *head = node;
-        } else {
-                node->next = *head;
-                *head = node;
-        }
-}
-
-static void *
-mptsas_hash_rem(mptsas_hash_table_t *hashtab, uint64_t key1,
-    mptsas_phymask_t key2)
-{
-        mptsas_hash_node_t **head = NULL;
-        mptsas_hash_node_t *last = NULL, *cur = NULL;
-        mptsas_hash_data_t *data;
-        if (hashtab == NULL) {
-                return (NULL);
-        }
-        head = &(hashtab->head[key1 % MPTSAS_HASH_ARRAY_SIZE]);
-        cur = *head;
-        while (cur != NULL) {
-                data = cur->data;
-                if ((data->key1 == key1) && (data->key2 == key2)) {
-                        if (last == NULL) {
-                                (*head) = cur->next;
-                        } else {
-                                last->next = cur->next;
-                        }
-                        kmem_free(cur, sizeof (mptsas_hash_node_t));
-                        return (data);
-                } else {
-                        last = cur;
-                        cur = cur->next;
-                }
-        }
-        return (NULL);
-}
-
-static void *
-mptsas_hash_search(mptsas_hash_table_t *hashtab, uint64_t key1,
-    mptsas_phymask_t key2)
-{
-        mptsas_hash_node_t *cur = NULL;
-        mptsas_hash_data_t *data;
-        if (hashtab == NULL) {
-                return (NULL);
-        }
-        cur = hashtab->head[key1 % MPTSAS_HASH_ARRAY_SIZE];
-        while (cur != NULL) {
-                data = cur->data;
-                if ((data->key1 == key1) && (data->key2 == key2)) {
-                        return (data);
-                } else {
-                        cur = cur->next;
-                }
-        }
-        return (NULL);
-}
-
-static void *
-mptsas_hash_traverse(mptsas_hash_table_t *hashtab, int pos)
-{
-        mptsas_hash_node_t *this = NULL;
-
-        if (hashtab == NULL) {
-                return (NULL);
-        }
-
-        if (pos == MPTSAS_HASH_FIRST) {
-                hashtab->line = 0;
-                hashtab->cur = NULL;
-                this = hashtab->head[0];
-        } else {
-                if (hashtab->cur == NULL) {
-                        return (NULL);
-                } else {
-                        this = hashtab->cur->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;
-        return (this->data);
-}
-
-/*
  * Functions for SGPIO LED support
  */
 static dev_info_t *
 mptsas_get_dip_from_dev(dev_t dev, mptsas_phymask_t *phymask)
 {

@@ -15572,11 +15390,11 @@
          *
          * In addition, we do not support this operation for RAID volumes,
          * since there is no slot associated with them.
          */
         if (!(ptgt->m_deviceinfo & DEVINFO_DIRECT_ATTACHED) ||
-            ptgt->m_phymask == 0) {
+            ptgt->m_addr.mta_phymask == 0) {
                 return (ENOTTY);
         }
 
         bzero(&req, sizeof (req));
         bzero(&rep, sizeof (rep));