--- /dev/null	2014-06-12 17:28:22.000000000 +0100
+++ new/usr/src/uts/common/io/scsi/adapters/mpt_sas3/mptsas3_hash.c	2014-06-12 17:28:22.734271251 +0100
@@ -0,0 +1,216 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2014 Joyent, Inc.  All rights reserved.
+ * Copyright (c) 2014, Tegile Systems Inc. All rights reserved.
+ */
+
+#include <sys/scsi/adapters/mpt_sas3/mptsas3_hash.h>
+#include <sys/sysmacros.h>
+#include <sys/types.h>
+#include <sys/kmem.h>
+#include <sys/list.h>
+#include <sys/ddi.h>
+
+#ifdef lint
+extern refhash_link_t *obj_to_link(refhash_t *, void *);
+extern void *link_to_obj(refhash_t *, refhash_link_t *);
+extern void *obj_to_tag(refhash_t *, void *);
+#else
+#define	obj_to_link(_h, _o)	\
+	((refhash_link_t *)(((char *)(_o)) + (_h)->rh_link_off))
+#define	link_to_obj(_h, _l)	\
+	((void *)(((char *)(_l)) - (_h)->rh_link_off))
+#define	obj_to_tag(_h, _o)	\
+	((void *)(((char *)(_o)) + (_h)->rh_tag_off))
+#endif
+
+refhash_t *
+refhash_create(uint_t bucket_count, refhash_hash_f hash,
+    refhash_cmp_f cmp, refhash_dtor_f dtor, size_t obj_size, size_t link_off,
+    size_t tag_off, int km_flags)
+{
+	refhash_t *hp;
+	uint_t i;
+
+	hp = kmem_alloc(sizeof (refhash_t), km_flags);
+	if (hp == NULL)
+		return (NULL);
+	hp->rh_buckets = kmem_zalloc(bucket_count * sizeof (list_t), km_flags);
+	if (hp->rh_buckets == NULL) {
+		kmem_free(hp, sizeof (refhash_t));
+		return (NULL);
+	}
+	hp->rh_bucket_count = bucket_count;
+
+	for (i = 0; i < bucket_count; i++) {
+		list_create(&hp->rh_buckets[i], sizeof (refhash_link_t),
+		    offsetof(refhash_link_t, rhl_chain_link));
+	}
+	list_create(&hp->rh_objs, sizeof (refhash_link_t),
+	    offsetof(refhash_link_t, rhl_global_link));
+
+	hp->rh_obj_size = obj_size;
+	hp->rh_link_off = link_off;
+	hp->rh_tag_off = tag_off;
+	hp->rh_hash = hash;
+	hp->rh_cmp = cmp;
+	hp->rh_dtor = dtor;
+
+	return (hp);
+}
+
+void
+refhash_destroy(refhash_t *hp)
+{
+	ASSERT(list_is_empty(&hp->rh_objs));
+
+	kmem_free(hp->rh_buckets, hp->rh_bucket_count * sizeof (list_t));
+	kmem_free(hp, sizeof (refhash_t));
+}
+
+void
+refhash_insert(refhash_t *hp, void *op)
+{
+	uint_t bucket;
+	refhash_link_t *lp = obj_to_link(hp, op);
+
+	bucket = hp->rh_hash(obj_to_tag(hp, op)) % hp->rh_bucket_count;
+	list_link_init(&lp->rhl_chain_link);
+	list_link_init(&lp->rhl_global_link);
+	lp->rhl_flags = 0;
+	lp->rhl_refcnt = 0;
+	list_insert_tail(&hp->rh_buckets[bucket], lp);
+	list_insert_tail(&hp->rh_objs, lp);
+}
+
+static void
+refhash_delete(refhash_t *hp, void *op)
+{
+	refhash_link_t *lp = obj_to_link(hp, op);
+	uint_t bucket;
+
+	bucket = hp->rh_hash(obj_to_tag(hp, op)) % hp->rh_bucket_count;
+	list_remove(&hp->rh_buckets[bucket], lp);
+	list_remove(&hp->rh_objs, lp);
+	hp->rh_dtor(op);
+}
+
+void
+refhash_remove(refhash_t *hp, void *op)
+{
+	refhash_link_t *lp = obj_to_link(hp, op);
+
+	if (lp->rhl_refcnt > 0) {
+		lp->rhl_flags |= RHL_F_DEAD;
+	} else {
+		refhash_delete(hp, op);
+	}
+}
+
+void *
+refhash_lookup(refhash_t *hp, const void *tp)
+{
+	uint_t bucket;
+	refhash_link_t *lp;
+	void *op;
+
+	bucket = hp->rh_hash(tp) % hp->rh_bucket_count;
+	for (lp = list_head(&hp->rh_buckets[bucket]); lp != NULL;
+	    lp = list_next(&hp->rh_buckets[bucket], lp)) {
+		op = link_to_obj(hp, lp);
+		if (hp->rh_cmp(obj_to_tag(hp, op), tp) == 0 &&
+		    !(lp->rhl_flags & RHL_F_DEAD)) {
+			return (op);
+		}
+	}
+
+	return (NULL);
+}
+
+void *
+refhash_linear_search(refhash_t *hp, refhash_eval_f eval, void *arg)
+{
+	void *op;
+	refhash_link_t *lp;
+
+	for (lp = list_head(&hp->rh_objs); lp != NULL;
+	    lp = list_next(&hp->rh_objs, lp)) {
+		op = link_to_obj(hp, lp);
+		if (eval(op, arg) == 0)
+			return (op);
+	}
+
+	return (NULL);
+}
+
+void
+refhash_hold(refhash_t *hp, void *op)
+{
+	refhash_link_t *lp = obj_to_link(hp, op);
+
+	++lp->rhl_refcnt;
+}
+
+void
+refhash_rele(refhash_t *hp, void *op)
+{
+	refhash_link_t *lp = obj_to_link(hp, op);
+
+	ASSERT(lp->rhl_refcnt > 0);
+
+	if (--lp->rhl_refcnt == 0 && (lp->rhl_flags & RHL_F_DEAD))
+		refhash_remove(hp, op);
+}
+
+void *
+refhash_first(refhash_t *hp)
+{
+	refhash_link_t *lp;
+
+	lp = list_head(&hp->rh_objs);
+	if (lp == NULL)
+		return (NULL);
+
+	++lp->rhl_refcnt;
+
+	return (link_to_obj(hp, lp));
+}
+
+void *
+refhash_next(refhash_t *hp, void *op)
+{
+	refhash_link_t *lp;
+
+	lp = obj_to_link(hp, op);
+	while ((lp = list_next(&hp->rh_objs, lp)) != NULL) {
+		if (!(lp->rhl_flags & RHL_F_DEAD))
+			break;
+	}
+
+	refhash_rele(hp, op);
+	if (lp == NULL)
+		return (NULL);
+
+	++lp->rhl_refcnt;
+
+	return (link_to_obj(hp, lp));
+}
+
+boolean_t
+refhash_obj_valid(refhash_t *hp, const void *op)
+{
+	/* LINTED - E_ARG_INCOMPATIBLE_WITH_ARG_L */
+	const refhash_link_t *lp = obj_to_link(hp, op);
+
+	return ((lp->rhl_flags & RHL_F_DEAD) != 0);
+}
